package hiro.yoshioka.sql.notes;

import hiro.yoshioka.classmanager.ClassManager;
import hiro.yoshioka.sdh.DatabaseType;
import hiro.yoshioka.sdh.ResultSetMetaCopy;
import hiro.yoshioka.sdh.StringRecordData;
import hiro.yoshioka.sdh2.ResultSetDataHolder2;
import hiro.yoshioka.sql.engine.MirroringRequest;
import hiro.yoshioka.sql.engine.Request;
import hiro.yoshioka.sql.notes.reflect.WolfDatabase;
import hiro.yoshioka.sql.notes.reflect.WolfDocument;
import hiro.yoshioka.sql.notes.reflect.WolfDocumentCollection;
import hiro.yoshioka.sql.notes.reflect.WolfItem;
import hiro.yoshioka.sql.notes.reflect.WolfView;
import hiro.yoshioka.sql.params.ConnectionProperties;
import hiro.yoshioka.sql.params.DBResourceCapturingFilter;
import hiro.yoshioka.sql.params.DBUserPass;
import hiro.yoshioka.sql.resource.DBRoot;
import hiro.yoshioka.sql.resource.DBSchema;
import hiro.yoshioka.sql.resource.IDBSchema;
import hiro.yoshioka.sql.resource.IDBTable;
import hiro.yoshioka.sql.resource.INameFamily;
import hiro.yoshioka.sql.resource.notes.NotesDBTable;
import hiro.yoshioka.sql.resource.xml.DBTableValue;
import hiro.yoshioka.util.FileUtil;
import hiro.yoshioka.util.StringUtil;
import hiro.yoshioka.util.Util;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class NotesRunnerSelection extends AbsNotesRunner implements
		Callable<ResultSetDataHolder2> {
	INameFamily table;
	ConnectionProperties properties;
	int maxRowNum;
	String dominoSearchQuery;
	Set<String> unidSet;
	ResultSetDataHolder2 rdh2;
	List<ResultSetMetaCopy.MetaInfo> metaList = new ArrayList<ResultSetMetaCopy.MetaInfo>();
	private boolean makeBlobData;
	private boolean richTextConvertToHtml;

	public NotesRunnerSelection(ClassManager manager, Request request,
			ConnectionProperties properties, IDBTable table,
			String dominoSearchQuery, int maxRowNum, boolean makeBlobData,
			boolean richTextConvertToHtml) {
		super(manager, request, properties);
		this.table = table;
		this.dominoSearchQuery = dominoSearchQuery;
		this.properties = properties;
		if (request instanceof MirroringRequest) {
			this.makeBlobData = ((MirroringRequest) request).makeBlob;
			this.maxRowNum = ((MirroringRequest) request).maxRowNum;
			this.richTextConvertToHtml = ((MirroringRequest) request).richTextConvertHtml;
		} else {
			this.makeBlobData = makeBlobData;
			this.maxRowNum = maxRowNum;
			this.richTextConvertToHtml = richTextConvertToHtml;
		}
	}

	public NotesRunnerSelection(ClassManager manager, Request request,
			ConnectionProperties properties, IDBTable table,
			Set<String> unidSet, boolean makeBlobData,
			boolean richTextConvertToHtml) {
		super(manager, request, properties);
		this.table = table;
		this.properties = properties;
		this.unidSet = unidSet;
		if (request instanceof MirroringRequest) {
			this.makeBlobData = ((MirroringRequest) request).makeBlob;
			this.maxRowNum = ((MirroringRequest) request).maxRowNum;
			this.richTextConvertToHtml = ((MirroringRequest) request).richTextConvertHtml;
		} else {
			this.makeBlobData = makeBlobData;
			this.richTextConvertToHtml = richTextConvertToHtml;
		}
	}

	public static void main(java.lang.String[] args) {
		ConnectionProperties p = new ConnectionProperties();

		// dom
		p.setHost("10.0.0.100");
		p.setAuthenticate(new DBUserPass("user", "password"));

		p.setCaptureWithDDL(true);
		p.setCaptureWithColumnInfo(false);
		p.setCaptureWithViewInfo(false);

		p.setCapturingFilter(DBResourceCapturingFilter.MATCHES);
		p.addFilePathRegrex(".*hoge.*");
		ClassManager cm = new ClassManager();
		try {
			DBRoot root = new DBRoot();
			IDBSchema sc = new DBSchema(root);
			sc.setName("fuga");
			root.putResource(sc.getName(), sc);
			NotesDBTable tbl = new NotesDBTable(sc);
			tbl.setName("piyo");
			tbl.setAlias("Data1");
			cm.add_lib(new File(
					"C:/tools/eclipse/wk/WolfSQLParser/ext_lib/NCSO.jar"));
			NotesRunnerSelection sjd = new NotesRunnerSelection(cm, null, p,
					tbl, null, 20, true, false);
			ExecutorService ex = Executors.newSingleThreadExecutor();
			Future<ResultSetDataHolder2> future = ex.submit(sjd);

			ex.shutdown();
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}

	private boolean isView() {
		if (table == null) {
			return ((DBTableValue) table).isType_view();
		}
		return ((IDBTable) table).isView();
	}

	@Override
	public ResultSetDataHolder2 call() throws Exception {
		initClass();
		createSession();

		try {
			if (isView()) {
				return callView();
			} else {
				return callTable();
			}
		} finally {
			wolf_session.recycle();
		}
	}

	private void putMeta(WolfItem item) throws IllegalArgumentException,
			IllegalAccessException, InvocationTargetException {
		this.putMeta(item, StringUtil.EMPTY_STRING);
	}

	private void putMeta(WolfItem item, String postfix)
			throws IllegalArgumentException, IllegalAccessException,
			InvocationTargetException {
		for (ResultSetMetaCopy.MetaInfo info : metaList) {
			if (info.columnName.equals(item.getName() + postfix)) {
				return;
			}
		}
		ResultSetMetaCopy.MetaInfo info = new ResultSetMetaCopy.MetaInfo();
		info.columnName = item.getName() + postfix;
		info.columnDisplaySize = item.getType().getSize(item.getName());
		info.columnType = item.getType().getSQLTypes().getType();
		info.columnTypeName = item.getType().getSQLTypeName();
		info.scale = item.getType().getSize(item.getName());
		if (table.getParent() != null) {
			info.schemaName = table.getParent().getName();
		}
		info.tableName = table.getName();
		metaList.add(info);
	}

	private void putMeta(String stringColumnName)
			throws IllegalArgumentException, IllegalAccessException,
			InvocationTargetException {
		for (ResultSetMetaCopy.MetaInfo info : metaList) {
			if (info.columnName.equals(stringColumnName)) {
				return;
			}
		}
		ResultSetMetaCopy.MetaInfo info = new ResultSetMetaCopy.MetaInfo();
		info.columnDisplaySize = 4000;
		info.columnName = stringColumnName;
		info.columnType = Types.VARCHAR;
		info.columnTypeName = "VARCHAR";
		info.scale = 4000;
		if (table.getParent() != null) {
			info.schemaName = table.getParent().getName();
		}
		info.tableName = table.getName();
		metaList.add(info);
	}

	private void doclist2Rdh(WolfDocument doc) throws IllegalArgumentException,
			MalformedURLException, SecurityException, IllegalAccessException,
			InvocationTargetException, ClassNotFoundException,
			NoSuchMethodException {
		if (doc == null) {
			return;
		}
		Set<String> allKeySets = new LinkedHashSet<String>();
		for (WolfItem item : doc.getItems()) {
			if (item.isIgnoreItem()) {
				continue;
			}
			allKeySets.add(item.getName());
			putMeta(item);
			if (item.isRichText() && makeBlobData) {
				allKeySets.add(item.getName() + "_att");
				putMeta(item, "_att");
			}
		}
		allKeySets.add(AbsNotesRunner.UniversalID);
		putMeta(AbsNotesRunner.UniversalID);
		allKeySets.add(AbsNotesRunner.HttpURL);
		putMeta(AbsNotesRunner.HttpURL);
		allKeySets.add(AbsNotesRunner.NotesURL);
		putMeta(AbsNotesRunner.NotesURL);
		if (rdh2 == null) {
			rdh2 = new ResultSetDataHolder2(
					allKeySets.toArray(new String[allKeySets.size()]), null,
					DatabaseType.DOMINO);
		}

		for (WolfItem item : doc.getItems()) {
			if (item.isIgnoreItem()) {
				continue;
			}
			if (!allKeySets.contains(item.getName())) {
				allKeySets.add(item.getName());
				putMeta(item);
				rdh2.addColumn(item.getName(), null);
			}
		}
		StringRecordData[] no_row_records = new StringRecordData[rdh2
				.getNoRowKeys().length];
		for (int i = 0; i < no_row_records.length; i++) {
			no_row_records[i] = new StringRecordData(null);
		}
		for (String key : allKeySets) {
			// Object o = obj.getItemValueString(key);
			// if (o != null) {
			// System.out.println(o.getClass());
			// }
			try {
				int idx = rdh2.getIndexByName(key);
				if (AbsNotesRunner.UniversalID.equals(key)) {
					no_row_records[idx - 1] = new StringRecordData(
							doc.getUniversalID());
				} else if (AbsNotesRunner.HttpURL.equals(key)) {
					no_row_records[idx - 1] = new StringRecordData(
							doc.getHttpURL());
				} else if (AbsNotesRunner.NotesURL.equals(key)) {
					no_row_records[idx - 1] = new StringRecordData(
							doc.getNotesURL());
				} else {
					if (doc.hasItem(key) && idx >= 0) {
						WolfItem item = doc.getFirstItem(key);
						no_row_records[idx - 1] = getItemValue(doc, key);
						if (item.isRichText()) {
							if (this.richTextConvertToHtml) {
								no_row_records[idx - 1] = new StringRecordData(
										item.getRichText2HtmlString());
							}
							if (this.makeBlobData) {
								if (item.getName().matches("$Fonts")) {

								} else {
									String in = item.getName() + "_att";
									File outDir = new File(FileUtil.TMP_DIR,
											doc.getUniversalID());
									List<File> retFileList = item
											.saveAttachment(outDir);
									if (retFileList != null) {
										StringBuilder b = new StringBuilder();
										for (File f : retFileList) {
											if (b.length() > 0) {
												b.append(StringUtil.LINE_SEPARATOR);
											}
											b.append(f.getAbsolutePath());
										}
										no_row_records[rdh2.getIndexByName(in) - 1] = new StringRecordData(
												b.toString());
									}
								}
							}
						}
						item.recycle();
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		rdh2.addRow(no_row_records);

		// System.out.println(obj.generateXML());

	}

	public ResultSetDataHolder2 callTable() throws Exception {
		WolfDatabase database = getDatabaseByTable(table);

		if (database == null) {
			return null;
		}
		if (!database.isOpen()) {
			database.open();
		}
		try {
			if (unidSet == null) {
				String query = null;
				if (StringUtil.isEmpty(dominoSearchQuery)) {
					if (table.hasAlias()) {
						query = String.format("Form=\"%s\"", table.getAlias());
					} else {
						query = String.format("Form=\"%s\"", table.getName());
					}
				} else {
					query = this.dominoSearchQuery;
				}
				if (request != null) {
					request.beginTask(
							String.format("database.search[%s]", query), 1);
				}

				WolfDocumentCollection docs = database.search(query, maxRowNum);

				int count = docs.getCount();
				fLogger.info(String.format(
						"database.search q=[%s] result count [%d]", query,
						count));
				if (request != null) {
					request.beginTask(String.format(
							"Document selection[%s] total[%d]", query, count),
							count);
				}
				WolfDocument doc = docs.getFirstDocument();
				doclist2Rdh(doc);
				while (doc != null) {
					doc = docs.getNextDocument();
					doclist2Rdh(doc);
					if (rdh2.getRowCount() % 2 == 0) {
						if (request != null) {
							request.worked(2);
						}
					}
					if (rdh2.getRowCount() >= this.maxRowNum) {
						fLogger.info("break maxRowNum[" + rdh2.getRowCount()
								+ "]");
						break;
					}
					if (rdh2.getRowCount() % 50 == 49) {
						fLogger.info(String.format(
								"do gc. now row count [%d] %s",
								rdh2.getRowCount(), Util.getHeapInfo()));
						System.gc();
					}
				}

			} else {
				for (String unid : unidSet) {
					WolfDocument doc = database.getDocumentByUNID(unid);
					doclist2Rdh(doc);

					if (rdh2.getRowCount() >= maxRowNum) {
						fLogger.info("break [" + rdh2.getRowCount() + "]");
						break;
					}
					if (rdh2.getRowCount() % 50 == 49) {
						fLogger.info(String.format(
								"do gc. now row count [%d] %s",
								rdh2.getRowCount(), Util.getHeapInfo()));
						System.gc();
					}
				}
			}
		} catch (Exception ne) {
			ne.printStackTrace();
			System.out.println(ne.getLocalizedMessage());
		} finally {
		}
		if (rdh2 == null) {
			rdh2 = new ResultSetDataHolder2(new String[] { "no_records" },
					null, DatabaseType.DOMINO);
		} else {
			rdh2.setMeta(new ResultSetMetaCopy(metaList));
		}

		return rdh2;
	}

	public ResultSetDataHolder2 callView() throws Exception {
		ResultSetDataHolder2 rdh = null;

		WolfView view = getView(table);

		try {
			WolfDocument doc = view.getFirstDocument();
			while (doc != null) {
				doclist2Rdh(doc);
				doc = view.getNextDocument(doc);
			}
			System.out.println(rdh);
		} catch (Exception ne) {
			ne.printStackTrace();
			System.out.println(ne.getLocalizedMessage());
		} finally {
		}

		return rdh;

	}

	private StringRecordData getItemValue(WolfDocument obj, String key)
			throws IllegalArgumentException, IllegalAccessException,
			InvocationTargetException, SecurityException, NoSuchMethodException {
		Vector v = obj.getItemValue(key);
		if (v == null || v.size() == 0) {
			return new StringRecordData(null);
		}
		StringBuilder buf = new StringBuilder();
		buf.append(v.get(0));
		for (int i = 1; i < v.size(); i++) {
			buf.append(StringUtil.LINE_SEPARATOR).append(v.get(i));
		}
		return new StringRecordData(buf.toString());
	}

}
