package hiro.yoshioka.sql.util;

import hiro.yoshioka.sdh.ResultSetDataHolder;
import hiro.yoshioka.sdh.diff.DiffToResultSetDataHolder;
import hiro.yoshioka.sdh2.ResultSetDataHolder2;
import hiro.yoshioka.sql.ITransactionSQL;
import hiro.yoshioka.sql.engine.DifferenceInStructureRequest;
import hiro.yoshioka.sql.engine.MirroringRequest;
import hiro.yoshioka.sql.engine.SQLServerThread;
import hiro.yoshioka.sql.params.ConnectionProperties;
import hiro.yoshioka.sql.params.ConnectionSettingBean;
import hiro.yoshioka.sql.resource.DBResourceType;
import hiro.yoshioka.sql.resource.IDBSchema;
import hiro.yoshioka.sql.resource.IDBTable;
import hiro.yoshioka.sql.resource.view.DBResourceTreeSelection;
import hiro.yoshioka.util.StringUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;

public class DefaultDatabaseComparingDialog extends TitleAreaDialog {
	private static final int BTN_ID_EXECUTE = 5500;

	final ConnectionProperties originalConnectionProperties;
	Button btCasdade;
	private static final String DEF_SELECT_TARGET_SCHEMA = "-- select target schema --";
	private static final String DEF_ACTIVE_CONNECTION_IS_NOTHING = "-- another active connection is nothing --";
	private static final String DEF_SELECT_CONNECTION = "-- select connection --";
	private ConnectionProperties targetConnectionProperties;
	Composite innerSchema;
	ScrolledForm root;
	private DBResourceTreeSelection fDBResourceTreeSelection;
	private Map<String, Combo> private_schemaMapping = new HashMap<String, Combo>();
	protected MirroringRequest mirroring_request;
	protected DifferenceInStructureRequest diff_struct_request;
	private Label mainTaskLabel, subTaskLabel;
	private ProgressBar progressBar;
	private Display display;
	private Text txtBooleanTrue, txtBooleanFalse;
	protected Log fLogger = LogFactory.getLog(getClass());
	ResultSetDataHolder2[] rdhs, rdhs2;
	List<String> diffMessageList = new ArrayList<String>();
	private Set<DBResourceType> compareStructureTypeSet = new TreeSet<DBResourceType>();
	protected boolean withTableRecord;

	public DefaultDatabaseComparingDialog(Shell shell, ConnectionProperties p,
			DBResourceTreeSelection treeSelection) {
		super(shell);
		originalConnectionProperties = p;
		fDBResourceTreeSelection = treeSelection;
	}

	@Override
	protected Point getInitialSize() {
		int width = 600;
		if (getParentShell().getBounds().width >= 700) {
			width = 700;
		} else if (getParentShell().getBounds().width >= 800) {
			width = 800;
		} else if (getParentShell().getBounds().width >= 900) {
			width = 900;
		}
		return new Point(width, getInitialHeight());
	}

	protected int getInitialHeight() {
		return 580;
	}

	@Override
	protected boolean isResizable() {
		return true;
	}

	@Override
	public void create() {
		super.create();
		validate();
	}

	private void resetTitle() {
		String targetDisp = "XXX";
		if (targetConnectionProperties != null) {
			targetDisp = targetConnectionProperties.getDisplayString();
		}
		root.setText(String.format("Compare to %s and %s", targetDisp,
				originalConnectionProperties.getDisplayString()));
	}

	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		GridLayout gl = (GridLayout) parent.getLayout();
		gl.verticalSpacing = 0;
		gl.marginBottom = 0;
		gl.marginTop = 0;
		gl.marginHeight = 1;
		Button btExec = createButton(parent, BTN_ID_EXECUTE,
				"Execute Compare Process", false);

		createButton(parent, IDialogConstants.CANCEL_ID,
				IDialogConstants.CANCEL_LABEL, true);
	}

	protected void compare(Set<IDBTable> tables) {
		try {
			ArrayList<ResultSetDataHolder> rList = new ArrayList<ResultSetDataHolder>();
			ArrayList<ResultSetDataHolder> rList2 = new ArrayList<ResultSetDataHolder>();

			int i = 0;
			ITransactionSQL source_sql = SQLServerThread.getSQLServer()
					.getTransactionSQL(originalConnectionProperties);
			ITransactionSQL target_sql = SQLServerThread.getSQLServer()
					.getTransactionSQL(targetConnectionProperties);

			for (IDBTable table : tables) {
				i++;
				ResultSetDataHolder2 rdh = source_sql.getAllData2(table, null);
				ResultSetDataHolder2 rdh2 = target_sql.getAllData2(table, null);

				if (rdh != null && rdh2 != null) {
					rList.add(rdh);
					rList2.add(rdh2);
					DiffToResultSetDataHolder differ = new DiffToResultSetDataHolder();
					int[] dp = table.getPkPositions();
					if (dp.length == 0) {
						dp = new int[] { 0 };
					}
					for (int m = 0; m < dp.length; m++) {
						fLogger.info("Compare Key->" + dp[m]);
					}
					differ.diffConfigure(rdh, rdh2, dp);
					differ.diff();
					diffMessageList.add(differ.getDiffInfomation());

				}
			}
			rdhs = rList.toArray(new ResultSetDataHolder2[rList.size()]);
			rdhs2 = rList2.toArray(new ResultSetDataHolder2[rList2.size()]);
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(diffMessageList);
	}

	@Override
	protected void buttonPressed(int buttonId) {
		if (BTN_ID_EXECUTE == buttonId) {
			Set<IDBTable> tables = Collections.EMPTY_SET;
			if (compareStructureTypeSet.size() > 0) {
				diff_struct_request = new DifferenceInStructureRequest(
						this.originalConnectionProperties,
						this.targetConnectionProperties);
				for (DBResourceType rType : compareStructureTypeSet) {
					diff_struct_request.addResourceType(rType);
				}
				for (String key : private_schemaMapping.keySet()) {
					Combo c = private_schemaMapping.get(key);
					if (!c.getText().equals(DEF_SELECT_TARGET_SCHEMA)) {
						if (c.getText().startsWith("!-")) {
							diff_struct_request.putSchemaMapping(key,
									c.getToolTipText());
						} else {
							diff_struct_request.putSchemaMapping(key,
									c.getText());
						}
					}
				}
			}
			if (withTableRecord) {
				mirroring_request = new MirroringRequest(
						this.originalConnectionProperties,
						this.targetConnectionProperties);
				for (String key : private_schemaMapping.keySet()) {
					Combo c = private_schemaMapping.get(key);
					if (!c.getText().equals(DEF_SELECT_TARGET_SCHEMA)) {
						if (c.getText().startsWith("!-")) {
							mirroring_request.putSchemaMapping(key,
									c.getToolTipText());
						} else {
							mirroring_request
									.putSchemaMapping(key, c.getText());
						}
					}
				}
				for (IDBTable table : fDBResourceTreeSelection
						.getTableAndViewSet(true)) {
					mirroring_request.putMirroringTable(table.getParent()
							.getName(), table.getName(), table.isTable());
				}
				tables = fDBResourceTreeSelection.getTableAndViewSet(true);
			}
			compare(tables);
		}
		super.buttonPressed(buttonId);
	}

	private GridData createGridData2() {
		GridData gd = new GridData(GridData.FILL_HORIZONTAL
				| GridData.VERTICAL_ALIGN_BEGINNING);
		gd.horizontalSpan = 2;
		return gd;
	}

	protected Control createDialogArea(Composite parent) {
		getShell().setText("Compare Dialog");
		try {
			display = parent.getDisplay();
			FormToolkit toolkit = new FormToolkit(parent.getDisplay());
			root = toolkit.createScrolledForm(parent);
			resetTitle();

			root.setLayoutData(new GridData(GridData.FILL_BOTH));
			root.getBody().setLayout(new GridLayout(2, false));
			root.getBody().setLayoutData(new GridData(GridData.FILL_BOTH));

			Section compareObjectOptionSection = toolkit.createSection(
					root.getBody(), Section.EXPANDED | Section.TITLE_BAR);
			compareObjectOptionSection.setText("[1] Compare Object");
			Composite compareObjectOptionComposite = toolkit
					.createComposite(compareObjectOptionSection);
			compareObjectOptionComposite.setLayout(new GridLayout(2, false));
			toolkit.createLabel(compareObjectOptionComposite, "Structure(DDL):");
			Composite checkComposite = toolkit
					.createComposite(compareObjectOptionComposite);
			checkComposite.setLayout(new GridLayout(
					DBResourceType.COMPARE_SUPPORT_SET.size(), false));
			for (DBResourceType rType : DBResourceType.COMPARE_SUPPORT_SET) {
				final Button btCheck = toolkit.createButton(checkComposite,
						rType.name(), SWT.CHECK);
				btCheck.setData(rType);
				btCheck.addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						if (btCheck.getSelection()) {
							compareStructureTypeSet
									.add((DBResourceType) btCheck.getData());
						} else {
							compareStructureTypeSet
									.remove((DBResourceType) btCheck.getData());
						}
						validate();
					}
				});
			}
			toolkit.createLabel(compareObjectOptionComposite,
					"Table Record Value:");
			final Button btWithTableRecord = toolkit.createButton(
					compareObjectOptionComposite, "", SWT.CHECK);
			btWithTableRecord.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					withTableRecord = btWithTableRecord.getSelection();
					setEnableEquivalentDef(withTableRecord);
					validate();
				}

			});

			compareObjectOptionSection.setClient(compareObjectOptionComposite);
			compareObjectOptionSection.setLayoutData(createGridData2());
			// --------------------------------------------------------------------
			Section fuzzyOptionSection = toolkit.createSection(root.getBody(),
					Section.EXPANDED | Section.TITLE_BAR);
			fuzzyOptionSection.setText("[2] Equivalent definition");
			Composite fuzzyOptionComposite = toolkit
					.createComposite(fuzzyOptionSection);
			fuzzyOptionComposite.setLayout(new GridLayout(2, false));
			toolkit.createLabel(fuzzyOptionComposite, "Boolean(TRUE)|Bit(ON):");
			txtBooleanTrue = toolkit.createText(fuzzyOptionComposite,
					"true|TRUE|t|T|1|ON|○", SWT.SINGLE);
			txtBooleanTrue
					.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			txtBooleanTrue.setEditable(false);
			toolkit.createLabel(fuzzyOptionComposite,
					"Boolean(FALSE)|Bit(OFF):");
			txtBooleanFalse = toolkit.createText(fuzzyOptionComposite,
					"false|FALSE|f|F|0|OFF|×", SWT.SINGLE);
			txtBooleanFalse
					.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			txtBooleanFalse.setEditable(false);

			fuzzyOptionSection.setClient(fuzzyOptionComposite);
			fuzzyOptionSection.setLayoutData(createGridData2());
			setEnableEquivalentDef(false);
			// --------------------------------------------------------------------
			Section connectionSection = toolkit.createSection(root.getBody(),
					Section.EXPANDED | Section.TITLE_BAR);
			connectionSection.setText("[3] Target Connection");
			Composite innerC = toolkit.createComposite(connectionSection);
			innerC.setLayout(new GridLayout(1, false));

			ConnectionSettingBean cbean = SQLServerThread.getSQLServer()
					.getConnectionSettingBean();

			final Combo targetConnectionCombo = new Combo(innerC, SWT.READ_ONLY);
			Collection<ConnectionProperties> cons = cbean
					.getConnectedConnectionSet();
			if (cons.size() <= 1) {
				targetConnectionCombo.add(DEF_ACTIVE_CONNECTION_IS_NOTHING);
			} else {
				targetConnectionCombo.add(DEF_SELECT_CONNECTION);
			}
			for (ConnectionProperties con : cons) {
				if (!con.equals(originalConnectionProperties)) {
					targetConnectionCombo.add(con.getDisplayString());
					targetConnectionCombo.setData(con.getDisplayString(), con);
				}
			}
			targetConnectionCombo.select(0);

			targetConnectionCombo.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					Object o = targetConnectionCombo
							.getData(targetConnectionCombo.getText());
					if (o != null) {
						DefaultDatabaseComparingDialog.this.targetConnectionProperties = (ConnectionProperties) o;
						resetTargetConnection();
					}
				}

			});

			connectionSection.setClient(innerC);
			// connectionSection.setLayoutData(new
			// GridData(GridData.FILL_BOTH));
			// --------------------------------------------------------------------
			Section schemaSection = toolkit.createSection(root.getBody(),
					Section.EXPANDED | Section.TITLE_BAR);
			schemaSection.setText("[4] Schema Mapping");
			innerSchema = toolkit.createComposite(schemaSection);
			innerSchema.setLayout(new GridLayout(2, false));
			System.out.println("fsel.size="
					+ fDBResourceTreeSelection.getSchemaSet(true).size());
			for (IDBSchema schema : fDBResourceTreeSelection.getSchemaSet(true)) {
				Label schemaFrom = new Label(innerSchema, SWT.NONE);
				schemaFrom.setText(String.format("%s -> ", schema.getName()));
				Combo mappingCombo = new Combo(innerSchema, SWT.READ_ONLY);
				mappingCombo.setToolTipText(schema.getName());
				mappingCombo.setLayoutData(new GridData(
						GridData.FILL_HORIZONTAL));
				mappingCombo.add("<select [3]Target Connection>");
				mappingCombo.select(0);
				System.out.println("  schema.getName()=" + schema.getName());
				private_schemaMapping.put(schema.getName(), mappingCombo);
				mappingCombo.addSelectionListener(new SelectionAdapter() {
					public void widgetSelected(SelectionEvent e) {
						validate();
					}
				});
			}

			schemaSection.setClient(innerSchema);
			schemaSection.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			// --------------------------------------------------------------------
			if (showProgressSection()) {
				Section progress_section = toolkit.createSection(
						root.getBody(), Section.EXPANDED | Section.TITLE_BAR);
				progress_section.setText("Mirroring Progress");
				Composite innerProgress = toolkit
						.createComposite(progress_section);
				innerProgress.setLayout(new FillLayout(SWT.VERTICAL));
				progressBar = new ProgressBar(innerProgress, SWT.SMOOTH);
				mainTaskLabel = new Label(innerProgress, SWT.NONE);
				subTaskLabel = new Label(innerProgress, SWT.NONE);

				progress_section.setClient(innerProgress);
				GridData gd = new GridData(GridData.FILL_HORIZONTAL);
				gd.horizontalSpan = 2;
				progress_section.setLayoutData(gd);
			}

			return root;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return root;
	}

	private void setEnableEquivalentDef(boolean withTableRecord) {
		txtBooleanTrue.setEnabled(withTableRecord);
		txtBooleanFalse.setEnabled(withTableRecord);
	}

	protected boolean showProgressSection() {
		return true;
	}

	private void resetTargetConnection() {
		resetTitle();
		for (Entry<String, Combo> entry : private_schemaMapping.entrySet()) {
			Combo combo = entry.getValue();
			combo.clearSelection();
			combo.removeAll();
			ITransactionSQL sql = SQLServerThread.getSQLServer()
					.getTransactionSQL(targetConnectionProperties);
			combo.add(DEF_SELECT_TARGET_SCHEMA);
			int selectIdx = -1;
			for (String schemaName : sql.getSchemas()) {
				combo.add(schemaName);
				if (schemaName.equalsIgnoreCase(entry.getKey())) {
					selectIdx = combo.getItemCount() - 1;
				}
			}
			if (selectIdx < 0) {
				combo.select(0);
			} else {
				combo.select(selectIdx);
			}
		}
		validate();
	}

	private void validate() {
		String newErrorMessage = null;
		if (this.targetConnectionProperties == null) {
			if (SQLServerThread.getSQLServer().getConnectionSettingBean()
					.getConnectedConnectionSet().size() <= 1) {
				newErrorMessage = "Another connection is nothing. you should connect another connection.";
			} else {
				newErrorMessage = "Set target Connection.";
			}
		}
		if (compareStructureTypeSet.size() == 0 && !withTableRecord) {
			newErrorMessage = "Check at least one on [1]Section.";
		}
		if (StringUtil.isEmpty(newErrorMessage)) {
			for (String key : private_schemaMapping.keySet()) {
				Combo c = private_schemaMapping.get(key);
				if (c.getText().equals(DEF_SELECT_TARGET_SCHEMA)) {
					newErrorMessage = "Schema Mapping is nothing. [" + key
							+ "]";
					break;
				}
			}
		}
		setErrorMessage(newErrorMessage);
		getButton(BTN_ID_EXECUTE).setEnabled(newErrorMessage == null);
	}

	public ConnectionProperties getOriginalConnectionProperties() {
		return originalConnectionProperties;
	}

	public ConnectionProperties getTargetConnectionProperties() {
		return targetConnectionProperties;
	}

}