package asandatabasebrowser.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * テーブル情報
 * ２次元データとそのデータ定義を保持する。
 * <<model>>
 */
public class DbData {
	public static final int NONE = -1;
	public static final int INSERT = 0;
	public static final int UPDATE = 1;
	public static final int DELETE = 2;
	/** テーブル情報. TableInfo,または ResultSetInfo */
	public ITableInfo tableInfo;
	/** ArrayList<Object[]> */
	private ArrayList records;
	public DbData(ITableInfo tableInfo, ArrayList records) {
		assert tableInfo != null;
		assert records != null;
		this.tableInfo = tableInfo;
		this.records = records;
	}
	public ITableInfo getTableInfo() { return tableInfo; }
	public Object[] getRecord(int row) {
		if (records.get(row) instanceof EditingRecord) {
			EditingRecord editRec = (EditingRecord) records.get(row);
			return editRec.rec;
		} else {
			return (Object[]) records.get(row);
		}
	}
	public void setRecord(int row, EditingRecord rec) {
		assert rec != null;
		records.set(row, rec);
	}
	public void addRecord(EditingRecord rec) {
		assert rec != null;
		records.add(rec);
	}
	public int getRecordCount() {
		return records.size();
	}
	public int getMode(int row) {
		if (records.get(row) instanceof EditingRecord) {
			EditingRecord editRec = (EditingRecord) records.get(row);
			return editRec.mode;
		} else {
			return NONE;
		}
	}
	public Object getOriginalValue(int row, int col) {
		assert getMode(row) != NONE;
		EditingRecord editRec = (EditingRecord) records.get(row);
		return editRec.org[col];
	}
	public void editCancel(int row) {
		if (records.get(row) instanceof EditingRecord) {
			EditingRecord rec = (EditingRecord) records.get(row);
			switch (rec.mode) {
			case UPDATE:
			case DELETE:
				records.set(row, rec.org);
				break;
			case INSERT:
				records.remove(row);
				break;
			default:
				assert false: rec.mode;
			}
		} else {
			assert false: row;
		}
		
	}
	
	public void sort(Comparator comp) {
		Collections.sort(records, comp);
	}
	private static boolean equals(Object obj1, Object obj2) {
		if (obj1 == obj2) return true;	// 同一オブジェクトor両方null
		if ((obj1 == null) || (obj2 == null)) return false;	// 片方がnull
		return obj1.equals(obj2);
	}
	public String createSql(int row) {
		VvDatabase db = tableInfo.getDatabase();
		EditingRecord editRec = (EditingRecord) records.get(row);
		switch(editRec.mode) {
		case DbData.INSERT:
			return createInsertSql(db, editRec);
		case DbData.UPDATE:
			return createUpdateSql(db, editRec);
		case DbData.DELETE:
			return createDeleteSql(db, editRec);
		default:
			assert false: editRec.mode;
		}
		return null;
	}
	private String createInsertSql(VvDatabase db, EditingRecord editRec) {
		assert tableInfo instanceof TableInfo: tableInfo;
		TableInfo info = (TableInfo) tableInfo;
		StringBuffer sb = new StringBuffer();
		Object[] newRec = editRec.rec;
		sb.append("insert into ");
		sb.append(info.getSqlTableName());
		for (int i=0; i<info.getColumnCount(); i++) {
			if (i != 0) {
				sb.append("\n    ,");
			} else {
				sb.append(" (\n    ");
			}
			ColumnInfo col = info.getColumnInfo(i);
			sb.append(col.columnName);
		}
		sb.append("\n) values (\n");
		for (int i=0; i<info.getColumnCount(); i++) {
			if (i != 0) {
				sb.append("\n    ,");
			} else {
				sb.append("    ");
			}
			ColumnInfo col = info.getColumnInfo(i);
			String sqlvalue = db.getValueStr(col, newRec[i]);
			sb.append(sqlvalue);
		}
		sb.append("\n)");
		System.out.println(sb.toString());
		return sb.toString();
	}
	private String createUpdateSql(VvDatabase db, EditingRecord editRec) {
		assert tableInfo instanceof TableInfo: tableInfo;
		TableInfo info = (TableInfo) tableInfo;
		StringBuffer sb = new StringBuffer();
		sb.append("update ");
		sb.append(info.getSqlTableName());
		sb.append(" set \n    ");
		boolean first = true;
		Object[] newRec = editRec.rec;
		Object[] orgRec = editRec.org;
		for (int i=0; i<info.getColumnCount(); i++) {
			ColumnInfo col = info.getColumnInfo(i);
			if (! equals(orgRec[i], newRec[i])) {
				if (! first) {
					sb.append("\n    ,");
				}
				String sqlvalue = db.getValueStr(col, newRec[i]);
				sb.append(col.columnName+"="+sqlvalue);
				first = false;
			}
		}
		// 変更点が１件もなければnullを返す。
		if (first) return null;
		sb.append("\nwhere ");
		// PKがあるときは、PKを条件にする。
		if (info.pkList != null && info.pkList.size() > 0) {
			for (int i=0; i<info.pkList.size(); i++) {
				if (i != 0) {
					sb.append("\n    and ");
				}
				String pk = (String) info.pkList.get(i);
				int index = info.getColumnIndexByName(pk);
				assert index != -1: index;
				ColumnInfo col = info.getColumnInfo(index);
				if (orgRec[index] != null) {
					String sqlvalue = db.getValueStr(col, orgRec[index]);
					sb.append(col.columnName+"="+sqlvalue);
				} else {
					sb.append(col.columnName+" is null");
				}
			}
		} else {
			// PKがないときは、すべての値をキーにする
			for (int i=0; i<info.getColumnCount(); i++) {
				if (i != 0) {
					sb.append("\n    and ");
				}
				ColumnInfo col = info.getColumnInfo(i);
				if (orgRec[i] != null) {
					String sqlvalue = db.getValueStr(col, orgRec[i]);
					sb.append(col.columnName+"="+sqlvalue);
				} else {
					sb.append(col.columnName+" is null");
				}
			}
		}
		return sb.toString();
	}
	private String createDeleteSql(VvDatabase db, EditingRecord editRec) {
		assert tableInfo instanceof TableInfo: tableInfo;
		TableInfo info = (TableInfo) tableInfo;
		StringBuffer sb = new StringBuffer();
		sb.append("delete from ");
		sb.append(info.getSqlTableName());
		sb.append("\nwhere ");
		Object[] orgRec = editRec.org;
		// PKがあるときは、PKを条件にする。
		if (info.pkList != null && info.pkList.size() > 0) {
			for (int i=0; i<info.pkList.size(); i++) {
				if (i != 0) {
					sb.append("\n    and ");
				}
				String pk = (String) info.pkList.get(i);
				int index = info.getColumnIndexByName(pk);
				assert index != -1: index;
				ColumnInfo col = info.getColumnInfo(index);
				if (orgRec[index] != null) {
					String sqlvalue = db.getValueStr(col, orgRec[index]);
					sb.append(col.columnName+"="+sqlvalue);
				} else {
					sb.append(col.columnName+" is null");
				}
			}
		} else {
			// PKがないときは、すべての値をキーにする
			for (int i=0; i<info.getColumnCount(); i++) {
				if (i != 0) {
					sb.append("\n    and ");
				}
				ColumnInfo col = info.getColumnInfo(i);
				if (orgRec[i] != null) {
					String sqlvalue = db.getValueStr(col, orgRec[i]);
					sb.append(col.columnName+"="+sqlvalue);
				} else {
					sb.append(col.columnName+" is null");
				}
			}
		}
		return sb.toString();
	}

}

