package com.ftinc.si.assist.test;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;


public class FakeMethodRecord extends Record {
	public FakeMethodRecord() {
		super(0);
	}

	public FakeMethodRecord(int i) {
		super(i);
	}

	public String[] argTypes;//[classname,...]
	public String className;
	public String methodName;
	public String source;
	public String[][] fields;//[[仮想メンバ変数の名前、クラス名のリスト],..]。
	public String superName;//DBには入れない。classNameがInterfaceの場合、superを指定できる。
	public String version;
	
	//DBの結果を読み込む
	public void read(ResultSet r) throws SQLException {
		className = r.getString("ClassName");
		source = r.getString("Source");
		setArgTypes(r.getString("ArgTypes"));
		methodName = r.getString("MethodName");
		setFields(r.getString("Fields"));
		version = r.getString("Version");
	}
	
	//引数の数を返す
	public int numArgs() {
		if (argTypes == null) {
			return 0;
		}
		return argTypes.length;
	}

	//DB格納のためにJSONにする。
	public String jsonOfArgTypes() {
		if (argTypes != null) {
			return Tool.getJSONfromObject(argTypes);
		}
		return "";
	}
		
	//argTypesの初期化
	public void setArgTypes(String json) {
		if (json == null || json.length() == 0) {
			argTypes = new String[0];
		} else {
			argTypes = (String[]) Tool.getObjectfromJSON(String[].class, json);
		}
	}

	//仮想フィールドの数を返す
	public int numFields() {
		if (fields == null) {
			return 0;
		}
		return fields.length;
	}
			
	//DB格納のためにJSONにする。
	private String jsonOfFields() {
		if (fields != null && fields.length > 0 && fields[0] != null) {
			return Tool.getJSONfromObject(fields);
		}
		return "";
	}
			
	//fieldsの初期化
	public void setFields(String json) {
		if (json == null || json.length() == 0) {
			fields = new String[0][];
		} else {
			fields = (String[][]) Tool.getObjectfromJSON(String[][].class, json);
		}
	}
	
	//仮想フィールドの追加
	public void addField(String cname, String fname) {
		String[][] t_list = new String[numFields() + 1][2];
		
		for (int i = 0; i < numFields(); i++) {
			if (fields[i][0].equals(fname)) {
				//登録済み
				return;
			}
			t_list[i][0] = fields[i][0];
			t_list[i][1] = fields[i][1];
		}

		t_list[numFields()][0] = fname;
		t_list[numFields()][1] = cname;
		fields = t_list;
	}
		
	//仮想フィールドの型取得
	public String getFieldType(String fname) {
		for (int i = 0; i < numFields(); i++) {
			if (fields[i][0].equals(fname)) {
				return fields[i][1];
			}
		}
		return null;
	}

	
	//DB更新のSQLを出力
	public String getUpdateSQL() {
		if (removed && isNew()) {
			return null;//DBに未登録のまま削除
		} else if (removed) {
			String sql_where = " where \"ClassName\"='" + className + "' and \"MethodName\"='" + methodName 
					+ "' and \"ArgTypes\"='" + jsonOfArgTypes() + "' and \"Version\"='" + version + "'";
			return "delete from \"tbl_AssertRecord\" " + sql_where;
		}

		String t_sql = null;
		if (isNew()) {
			t_sql = "insert into \"tbl_FakeMethodRecord\" (\"MethodName\", \"ClassName\", \"ArgTypes\", \"Source\", \"Version\", \"Fields\")"
					+ "values ('" + methodName + "','" + className + "','" + jsonOfArgTypes() + "','" 
					+ _source() + "','" + version + "','" + jsonOfFields() + "')";
		} else if (isUpdated()) {
			String sql_where = " where \"ClassName\"='" + className + "' and \"MethodName\"='" + methodName 
					+ "' and \"ArgTypes\"='" + jsonOfArgTypes() + "' and \"Version\"='" + version + "'";
			t_sql = "update \"tbl_FakeMethodRecord\" set \"Source\"='" + _source() + "', \"Fields\"='" + jsonOfFields() + "'" + sql_where;
		}
		return t_sql;
	}
	
	//実質的に内容が異なる場合、true。実質が同じならfalse
	public boolean differed(String cname, String mname, String[] argtypes, String src) {
		if (className.equals(cname) && methodName.equals(mname) && Arrays.equals(argTypes,argtypes)) {
			if (source != null) {
				return !source.equals(src);
			} else if (src == null) {
				return false;
			}
		}
		return true;
	}
	
	//dummy:equals上書きの警告を回避するため。
	public int hashCode() {
		return 42;
	}
	
	//FakeMethodRecordの等価判定。
	public boolean equals(Object obj) {
		if (obj != null && obj.getClass().getName().equals("com.ftinc.si.assist.test.FakeMethodRecord")) {
			FakeMethodRecord frec = (FakeMethodRecord) obj;
			if (className.equals(frec.className)) {
				if (methodName.equals(frec.methodName)) {
					if (argTypes == null) {
						if (frec.argTypes == null) {
							return true;
						}
					} else if (argTypes == frec.argTypes) {
						return true;
					}
				}
			}
		}
		return false;
	}
	
	//登録時の特殊文字をエスケープ
	private String _source() {
		return esq(source);
	}
	
	//クラスcnameに実装されている仮想メンバとクラス名のマップを作成して返す。
	public static HashMap<String, String> getVFields(String cname) {
		HashMap<String, String> t_map = new HashMap<String, String>();
		cname = cname.replace("?", "");

		ArrayList<FakeMethodRecord> t_list = Tool._db().getFakeMethods(cname, Tool.version);
		for (int i = 0; i < t_list.size(); i++) {
			String[][] t_flds = t_list.get(i).fields;
			for (int j = 0; j < t_flds.length; j++) {
				if (!t_map.containsKey(t_flds[j][0])) {
					t_map.put(t_flds[j][0], t_flds[j][1]);
				}
			}
		}
		return t_map;
	}
}
