package hiro.yoshioka.sql.evernote;

import hiro.yoshioka.sdh.DatabaseType;
import hiro.yoshioka.sdh2.ResultSetDataHolder2;
import hiro.yoshioka.sql.AbsNoSQL;
import hiro.yoshioka.sql.SQLExecutionStatus;
import hiro.yoshioka.sql.engine.GettingResourceRequest;
import hiro.yoshioka.sql.engine.MirroringRequest;
import hiro.yoshioka.sql.engine.Request;
import hiro.yoshioka.sql.engine.SQLOperationType;
import hiro.yoshioka.sql.engine.TransactionRequest;
import hiro.yoshioka.sql.params.ConnectionProperties;
import hiro.yoshioka.sql.params.DBUserPass;
import hiro.yoshioka.sql.resource.DBRoot;
import hiro.yoshioka.sql.resource.IDBColumn;
import hiro.yoshioka.sql.resource.IDBResource;
import hiro.yoshioka.sql.resource.IDBSchema;
import hiro.yoshioka.sql.resource.IDBTable;
import hiro.yoshioka.sql.resource.TableType;
import hiro.yoshioka.sql.resource.evernote.EvernoteColumnType;
import hiro.yoshioka.sql.resource.evernote.EvernoteDBColumn;
import hiro.yoshioka.sql.resource.evernote.EvernoteDBSchema;
import hiro.yoshioka.sql.resource.evernote.EvernoteDBTable;
import hiro.yoshioka.sql.resource.evernote.EvernoteSchemaType;
import hiro.yoshioka.sql.resource.evernote.EvernoteTableType;
import hiro.yoshioka.sql.resource.evernote.EvernoteTag;
import hiro.yoshioka.util.StringUtil;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.THttpClient;
import org.apache.thrift.transport.TTransportException;

import com.evernote.edam.error.EDAMErrorCode;
import com.evernote.edam.error.EDAMNotFoundException;
import com.evernote.edam.error.EDAMSystemException;
import com.evernote.edam.error.EDAMUserException;
import com.evernote.edam.notestore.NoteCollectionCounts;
import com.evernote.edam.notestore.NoteFilter;
import com.evernote.edam.notestore.NoteStore;
import com.evernote.edam.notestore.NoteStore.Client;
import com.evernote.edam.type.LinkedNotebook;
import com.evernote.edam.type.Notebook;
import com.evernote.edam.type.SharedNotebook;
import com.evernote.edam.type.Tag;
import com.evernote.edam.type.User;
import com.evernote.edam.userstore.AuthenticationResult;
import com.evernote.edam.userstore.Constants;
import com.evernote.edam.userstore.PublicUserInfo;
import com.evernote.edam.userstore.UserStore;

public class EverNoteSQL extends AbsNoSQL {
	private static final String sabdbox_evernoteHost = Messages
			.getString("EverNoteSQL.Sandbox"); //$NON-NLS-1$
	private static final String www_evernoteHost = Messages
			.getString("EverNoteSQL.WWW"); //$NON-NLS-1$
	private static final String userAgent = "WolfDBManager (Java) " //$NON-NLS-1$
			+ Constants.EDAM_VERSION_MAJOR + "." + Constants.EDAM_VERSION_MINOR; //$NON-NLS-1$
	private static final String DEF_CONSUMER_KEY = Messages
			.getString("EverNoteSQL.DEF_CONSUMER_KEY"); //$NON-NLS-1$
	private static final String DEF_CONSUMER_SECRET = Messages
			.getString("EverNoteSQL.DEF_CONSUMER_SECRET"); //$NON-NLS-1$
	private Map<String, NoteStore.Client> shardNoteStoreMap;
	private Map<String, Integer> userNameTosharedIdMap;
	private UserStore.Client userStore;
	private User loginUser;
	// private NoteStore.Client noteStore;
	private String authToken;

	public EverNoteSQL() {
	}

	@Override
	public boolean canDoOperation(SQLOperationType operation) {
		switch (operation) {
		case CREATE_DATABASE:
			return true;
		case DROP_DATABASE:
			return false;
		default:
			return super.canDoOperation(operation);
		}
	}

	protected int getSharedId(String userName) throws EDAMNotFoundException,
			EDAMSystemException, EDAMUserException, TException {
		if (this.userNameTosharedIdMap == null) {
			this.userNameTosharedIdMap = new HashMap<String, Integer>();
		}
		Integer ret = this.userNameTosharedIdMap.get(userName);
		if (ret == null) {
			PublicUserInfo puInfo = userStore.getPublicUserInfo(userName);
			ret = puInfo.getUserId();
			this.userNameTosharedIdMap.put(userName, ret);
		}
		return ret;
	}

	protected NoteStore.Client getNoteStoreClient(String shardId)
			throws TTransportException {
		if (this.shardNoteStoreMap == null) {
			this.shardNoteStoreMap = new HashMap<String, NoteStore.Client>();
		}
		NoteStore.Client ret = this.shardNoteStoreMap.get(shardId);
		if (ret == null) {
			String evernoteHost = getEvernoteHost();
			String noteStoreUrlBase = "https://" + evernoteHost + "/edam/note/"; //$NON-NLS-1$ //$NON-NLS-2$

			String sharedNoteStoreUrl = noteStoreUrlBase + shardId;
			THttpClient noteStoreTrans = new THttpClient(sharedNoteStoreUrl);
			noteStoreTrans.setCustomHeader("User-Agent", userAgent); //$NON-NLS-1$
			TBinaryProtocol noteStoreProt = new TBinaryProtocol(noteStoreTrans);
			NoteStore.Client sharedNoteStore = new NoteStore.Client(
					noteStoreProt, noteStoreProt);
			ret = sharedNoteStore;
			this.shardNoteStoreMap.put(shardId, ret);
		}
		return ret;
	}

	private long getNoteBookCount(NoteCollectionCounts coteCollectionCounts) {
		long sum = 0;
		if (coteCollectionCounts != null) {
			for (Integer ii : coteCollectionCounts.getNotebookCounts().values()) {
				sum += ii;
			}
		}
		return sum;
	}

	public long count(IDBTable table) throws SQLException {
		if (table == null) {
			return 0L;
		}
		long sum = 0;
		EvernoteDBSchema schema = (EvernoteDBSchema) table.getParent();
		EvernoteSchemaType schemaType = schema.getSchemaType();
		EvernoteDBTable eTable = cast(table);
		EvernoteTableType tableType = eTable.getEvernoteTableType();
		try {
			NoteFilter filter = new NoteFilter();
			NoteCollectionCounts c = null;
			switch (schemaType) {
			case NoteBook:
				filter.setNotebookGuid(eTable.getGuid());
				c = getMyNoteStoreClient().findNoteCounts(authToken, filter,
						false);
				return getNoteBookCount(c);
			case LinkedNoteBook:
				filter.setNotebookGuid(eTable.getRefferencedGuid());
				System.out.println("Cguid=" + eTable.getRefferencedGuid());
				c = getNoteStoreClient(eTable.getSharedId()).findNoteCounts(
						authToken, filter, false);
				return getNoteBookCount(c);
			case SharedNoteBook:
				filter.setNotebookGuid(eTable.getGuid());
				c = getMyNoteStoreClient().findNoteCounts(authToken, filter,
						false);
				for (Integer ii : c.getNotebookCounts().values()) {
					sum += ii;
				}
				return sum;
			case Tags:
				List<String> tagSets = new ArrayList<String>();
				tagSets.add(eTable.getGuid());
				filter.setTagGuids(tagSets);
				c = getMyNoteStoreClient().findNoteCounts(authToken, filter,
						false);
				for (Integer ii : c.getNotebookCounts().values()) {
					sum += ii;
				}
				return sum;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return 0;
	}

	final public DatabaseType getDatabaseType() {
		return DatabaseType.EVERNOTE;
	}

	protected DBRoot getMetaData(GettingResourceRequest request) {
		DBRoot root = getRoot();
		try {
			capturing = true;
			if (request.canceld()) {
				return null;
			}

			root = new DBRoot(Messages.getString("EverNoteSQL.DBName")); //$NON-NLS-1$
			setRoot(root);
			root.setPropertyValue("This DB Resources updated at ", String //$NON-NLS-1$
					.format("%tF %tT", new java.util.Date(), //$NON-NLS-1$
							new java.util.Date()));
			createSchemas(root);
		} catch (Throwable e) {
			e.printStackTrace();
			fLogger.error(e);
			return null;
		} finally {
			capturing = false;
		}
		return root;
	}

	@Override
	public boolean doOperation(SQLOperationType operation, Request request)
			throws SQLException {
		TransactionRequest treq = null;
		if (request instanceof TransactionRequest) {
			treq = (TransactionRequest) request;
		}
		rsUtil.setMakeBlobData(request.makeBlob);

		boolean retCode = true;
		if (SQLOperationType.CONNECT == operation) {
			ConnectionProperties prop = request.getConnectionProperties();
			return connect(prop);
		} else if (SQLOperationType.CLOSE == operation) {
			ConnectionProperties prop = request.getConnectionProperties();
			return close();
		}
		long time = System.currentTimeMillis();

		try {
			switch (operation) {
			case RESOURCE_MIRRORING:
				MirroringRequest mirroring_request = (MirroringRequest) request;
				retCode = createMirroredTableTo(mirroring_request);
				break;
			case COUNT:
				treq.setResultCount(count(treq.getIDBTable()));
				break;
			case RESOURCE_CAPTION:
				getMetaData((GettingResourceRequest) request);
				break;
			case EXPLAIN_PLAN:
				break;
			case SELECT_SESSION:
				break;
			case SELECT_LOCK:
				break;
			case PREPARED_EXECUTE_QUERY:
				notifyExecute(SQLExecutionStatus.BEFORE_EXECUTE);
				EvernoteDBTable table = (EvernoteDBTable) treq.getIDBTable();
				EvernoteSchemaType schemaType = ((EvernoteDBSchema) table
						.getParent()).getSchemaType();
				switch (schemaType) {
				case NoteBook:
				case LinkedNoteBook:
				case SharedNoteBook:
					treq.setRDH(getRdh(schemaType,
							table.getEvernoteTableType(),
							cnvList(treq.getSelectColumnList()),
							translateParams(treq.getFirstParams(), table)));
					// treq.setRDH(getFollowers(-1, null));
					break;
				default:
					ResultSetDataHolder2 rdh = new ResultSetDataHolder2(
							new String[] { "message" }, null, //$NON-NLS-1$
							DatabaseType.UNKNOWN);
					rdh.addRow(new String[] { String
							.format("Schema[%s] is not support yet.", schemaType.name()) }); //$NON-NLS-1$
					treq.setRDH(rdh);
					break;
				// treq.setRDH(getFollowers(-1, null));
				}
				break;
			case PREPARED_EXECUTE:
				break;
			default:
				return super.doOperation(operation, request);
			}
		} catch (Exception e) {
			e.printStackTrace();

		}
		time = System.currentTimeMillis() - time;
		if (treq == null) {
			notifyExecute(SQLExecutionStatus.AFTER_EXECUTE, "0", //$NON-NLS-1$
					String.valueOf(time));
		} else {
			notifyExecute(SQLExecutionStatus.AFTER_EXECUTE,
					String.valueOf(treq.getReturnedRowCount()),
					String.valueOf(time));
		}
		return retCode;

	}

	private List<EvernoteColumnType> cnvList(List<String> selectColumnList) {
		if (selectColumnList == null || selectColumnList.size() == 0) {
			return null;
		}
		List<EvernoteColumnType> retList = new ArrayList<EvernoteColumnType>();
		for (String columnName : selectColumnList) {
			EvernoteColumnType type = EvernoteColumnType.valueOf(columnName);
			if (type != null) {
				retList.add(type);
			}
		}
		return retList;
	}

	private EvernoteDBTable createNoteBookTable(EvernoteDBSchema schema,
			Notebook book) {
		EvernoteDBTable table = new EvernoteDBTable(schema,
				EvernoteTableType.NoteBook);
		table.setTableType(TableType.TABLE);
		table.setName(book.getName());
		table.setGuid(book.getGuid());
		if (schema != null) {
			schema.putTable(table);
		}
		for (EvernoteColumnType columnType : EvernoteColumnType
				.getColumnTypeListOf(EvernoteTableType.NoteBook)) {
			IDBColumn column = createColumn(table, columnType);
		}
		return table;
	}

	public void createSchemas(DBRoot root) {
		for (EvernoteSchemaType schemaType : EvernoteSchemaType.values()) {

			EvernoteDBSchema schema = new EvernoteDBSchema(root, schemaType);
			root.putResource(schema.getName(), schema);
			try {
				Client noteStore = getMyNoteStoreClient();
				switch (schemaType) {
				case NoteBook:
					for (Notebook book : noteStore.listNotebooks(authToken)) {
						EvernoteDBTable table = createNoteBookTable(schema,
								book);
					}
					break;
				case SharedNoteBook:
					for (SharedNotebook book : noteStore
							.listSharedNotebooks(authToken)) {
						EvernoteDBTable table = new EvernoteDBTable(schema,
								EvernoteTableType.SharedNoteBook);
						table.setTableType(TableType.TABLE);

						table.setName(book.getUsername());
						table.setGuid(book.getNotebookGuid());
						schema.putTable(table);
						for (EvernoteColumnType columnType : EvernoteColumnType
								.getColumnTypeListOf(table
										.getEvernoteTableType())) {
							IDBColumn column = createColumn(table, columnType);
						}
					}
					break;
				case LinkedNoteBook:
					for (LinkedNotebook book : noteStore
							.listLinkedNotebooks(authToken)) {
						System.out.println("make LinkedNoteBook:" + book);
						EvernoteDBTable table = createLinkedNoteBookTable(
								schema, book);
					}
					break;
				case Tags:
					for (Tag tag : noteStore.listTags(authToken)) {
						EvernoteTag eTag = new EvernoteTag(schema, tag);
						schema.putTag(eTag);
						NoteFilter filter = new NoteFilter();
						filter.addToTagGuids(tag.getGuid());
						NoteCollectionCounts counts = noteStore.findNoteCounts(
								authToken, filter, false);
						int sum = 0;
						System.out.println(eTag + " " + counts);
						System.out
								.println("   =>" + counts.getNotebookCounts());
						for (Integer cntOfBook : counts.getNotebookCounts()
								.values()) {
							sum += cntOfBook;
						}
						eTag.setNoteCount(sum);
					}
					break;
				}
				noteStore.listLinkedNotebooks(authToken);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}

	private Client getMyNoteStoreClient() throws TTransportException {
		return getNoteStoreClient(loginUser.getShardId());
	}

	// private Notebook getPublicNotebook(String userName, String uri)
	// throws EDAMNotFoundException, EDAMSystemException,
	// EDAMUserException, TException {
	// int sharedId = getSharedId(userName);
	// Client sharedNoteStore = getShardNoteStore(userName);
	//
	// Notebook pBook = sharedNoteStore.getPublicNotebook(sharedId, uri);
	// return pBook;
	// }

	private EvernoteDBTable createLinkedNoteBookTable(EvernoteDBSchema schema,
			LinkedNotebook book) throws EDAMNotFoundException,
			EDAMSystemException, EDAMUserException, TException {
		EvernoteDBTable table = new EvernoteDBTable(schema,
				EvernoteTableType.LinkedNoteBook);
		table.setTableType(TableType.TABLE);

		PublicUserInfo puInfo = userStore.getPublicUserInfo(book.getUsername());
		Client sharedNoteStore = getNoteStoreClient(book.getShardId());

		Notebook pBook = sharedNoteStore.getPublicNotebook(puInfo.getUserId(),
				book.getUri());
		table.setName(book.getShareName());
		table.setComment(book.getUsername());
		table.setGuid(pBook.getGuid());
		table.setRefferencedGuid(pBook.getGuid());
		table.setUserName(book.getUsername());
		table.setUri(book.getUri());
		table.setSharedId(book.getShardId());
		schema.putTable(table);

		// NoteFilter nf = new NoteFilter();
		// nf.setNotebookGuid(pBook.getGuid());
		// NoteList nll = sharedNoteStore.findNotes(authToken, nf,
		// 0,
		// 100);
		// System.out.println("nll=" + nll);
		// for (SharedNotebook sn : sharedNoteStore
		// .listSharedNotebooks(aResult
		// .getAuthenticationToken())) {
		// System.out.println("mysn=" + sn);
		// System.out.println("skey =" + sn.getShareKey());
		// }

		for (EvernoteColumnType columnType : EvernoteColumnType
				.getColumnTypeListOf(EvernoteTableType.NoteBook)) {
			IDBColumn column = createColumn(table, columnType);
		}
		return table;
	}

	private IDBColumn createColumn(IDBTable table, EvernoteColumnType columnType) {
		EvernoteDBColumn column = new EvernoteDBColumn(table, columnType);
		column.setName(columnType.name());
		switch (columnType) {
		case guid:
		case notebookGuid:
			column.setSize(38);
			break;
		default:
			switch (columnType.getColumnType()) {
			case VARCHAR:
				column.setSize(4000);
				break;
			case INTEGER:
			case NUMERIC:
				column.setSize(30);
				break;
			case DOUBLE:
				column.setSize(30);
				column.setDecimalDigits(3);
				break;
			default:
				break;
			}
			break;
		}
		column.setConditionParameter(columnType.getSearchableType());
		column.setOnClickable(columnType.isOnClickable());
		column.setPKey(columnType.isPrimaryKey());
		column.setDataType(columnType.getColumnType());
		column.setDataTypeString(columnType.getDataTypeString());
		table.putResource(column.getName(), column);
		return column;
	}

	@Override
	public Set<String> getSchemas() {
		// List all of the notes in the user's account
		Set<String> retSet = new LinkedHashSet<String>();
		try {
			for (Notebook book : getMyNoteStoreClient()
					.listNotebooks(authToken)) {
				retSet.add(book.getName());
			}
		} catch (Exception e) {
			fLogger.fatal(StringUtil.EMPTY_STRING, e);
		}
		return retSet;
	}

	@Override
	public Set<String> getTables(String name) {
		try {
			EvernoteSchemaType schemaType = EvernoteSchemaType.valueOf(name);
			Set<String> retSet = new LinkedHashSet<String>();
			Client noteStore = getMyNoteStoreClient();
			switch (schemaType) {
			case NoteBook:
				for (Notebook book : noteStore.listNotebooks(authToken)) {
					retSet.add(book.getName());
				}
				break;
			case SharedNoteBook:
				for (SharedNotebook book : noteStore
						.listSharedNotebooks(authToken)) {
					retSet.add(book.getUsername());
				}
				break;
			case LinkedNoteBook:
				for (LinkedNotebook book : noteStore
						.listLinkedNotebooks(authToken)) {
					retSet.add(book.getShareName());
				}
				break;
			case Tags:
				break;
			}
			return retSet;
		} catch (Exception e) {
			return Collections.EMPTY_SET;
		}
	}

	@Override
	public boolean supportResultSet() {
		return true;
	}

	@Override
	public ResultSet getAllData(IDBTable table) throws SQLException {
		IDBResource p = table.getParent();
		EvernoteDBTable eTable = cast(table);
		try {
			EvernoteSchemaType schemaType = null;
			EvernoteTableType tableType = null;
			if (p instanceof EvernoteDBSchema) {
				schemaType = ((EvernoteDBSchema) table.getParent())
						.getSchemaType();

				tableType = ((EvernoteDBTable) table).getEvernoteTableType();
			} else {
				schemaType = EvernoteSchemaType.valueOf(p.getName());
				tableType = eTable.getEvernoteTableType();
			}
			Map<String, Object> params = translateParams(null, eTable);
			return getRs(schemaType, tableType, null, params);
		} catch (Exception e) {
			fLogger.warn(StringUtil.EMPTY_STRING, e);
		}
		return null;
	}

	private EvernoteDBTable cast(IDBTable table) {
		if (table instanceof EvernoteDBTable) {
			return (EvernoteDBTable) table;
		}
		IDBSchema schema = (IDBSchema) table.getParent();
		try {
			switch (EvernoteSchemaType.valueOf(schema.getName())) {
			case NoteBook:
				for (Notebook book : getMyNoteStoreClient().listNotebooks(
						authToken)) {
					if (book.getName()
							.replaceAll(StringUtil.HALF_SPACE__STRING,
									StringUtil.EMPTY_STRING)
							.equals(table.getName())) {
						return createNoteBookTable(null, book);
					}
				}
				break;
			case LinkedNoteBook:
				for (LinkedNotebook book : getMyNoteStoreClient()
						.listLinkedNotebooks(authToken)) {
					if (book.getShareName()
							.replaceAll(StringUtil.HALF_SPACE__STRING,
									StringUtil.EMPTY_STRING)
							.equals(table.getName())) {
						return createLinkedNoteBookTable(null, book);
					}
				}
				break;
			case SharedNoteBook:
				break;
			case Tags:
				break;
			}
		} catch (Exception e) {
			fLogger.warn(StringUtil.EMPTY_STRING, e);
		}
		return null;
	}

	@Override
	public ResultSetDataHolder2 getAllData2(IDBTable table, Request request)
			throws SQLException {
		if (request != null) {
			rsUtil.setMakeBlobData(request.makeBlob);
		}
		ResultSet rs = getAllData(table);
		if (rs != null) {
			ResultSetDataHolder2 rdh2 = rsUtil.RS2RDH(DatabaseType.EVERNOTE,
					rs, true);
			if (rdh2 != null) {
				rdh2.setTableName(table.getComment());
				rdh2.setTableNameE(table.getName());
			}
			return rdh2;
		}
		return null;
	}

	public ResultSetDataHolder2 getRdh(EvernoteSchemaType schemaType,
			EvernoteTableType tableType,
			List<EvernoteColumnType> selectColumnList,
			Map<String, Object> params) throws Exception {

		return rsUtil.RS2RDH(DatabaseType.EVERNOTE,
				getRs(schemaType, tableType, selectColumnList, params), true);
	}

	private Map<String, Object> translateParams(Map<String, Object> params,
			EvernoteDBTable eTable) {
		if (params == null) {
			params = new HashMap<String, Object>();
		}
		params.put(EvernoteColumnType.notebookGuid.name(), eTable.getGuid());
		if (eTable.getEvernoteTableType().isLinkedNotebook()) {
			params.put(EvernoteColumnType.shardId.name(), eTable.getSharedId());
			params.put(EvernoteColumnType.notebookGuid.name(),
					eTable.getRefferencedGuid());
		}
		return params;
	}

	private ResultSet getRs(EvernoteSchemaType schemaType,
			EvernoteTableType tableType,
			List<EvernoteColumnType> selectColumnList,
			Map<String, Object> params) throws Exception {
		Client noteStore = getMyNoteStoreClient();

		if (tableType.isLinkedNotebook() && params != null) {
			if (params.containsKey(EvernoteColumnType.shardId.name())) {
				String sharedId = (String) params
						.get(EvernoteColumnType.shardId.name());
				noteStore = getNoteStoreClient(sharedId);
				fLogger.info("noteStore changed:" + sharedId);
			}
		}
		return new EvernoteResultSet(noteStore, this.authToken, schemaType,
				tableType, selectColumnList, params, rsUtil);
	}

	private String getEvernoteHost() {
		if (this._info == null) {
			return www_evernoteHost;
		}
		String host = this._info.getHost();
		if (validateHost(host) == null) {
			return host;
		}
		return www_evernoteHost;
	}

	public static String validateHost(String host) {
		if (www_evernoteHost.equals(host) || sabdbox_evernoteHost.equals(host)) {
			return null;
		}
		return Messages.getString("EverNoteSQL.ValidationHostMessage"); //$NON-NLS-1$
	}

	@Override
	public boolean createDatabase(String name, Properties properties)
			throws SQLException {
		boolean ret = true;
		Notebook notebook = new Notebook();
		try {
			notebook.setName(name);
			getMyNoteStoreClient().createNotebook(authToken, notebook);
		} catch (Exception e) {
			ret = false;
			fLogger.fatal(StringUtil.EMPTY_STRING, e);
		}
		return ret;
	}

	@Override
	public boolean connect(ConnectionProperties properties) throws SQLException {

		THttpClient userStoreTrans = null;
		try {
			this._info = properties;
			String evernoteHost = getEvernoteHost();
			String userStoreUrl = "https://" + evernoteHost + "/edam/user"; //$NON-NLS-1$ //$NON-NLS-2$
			String noteStoreUrlBase = "https://" + evernoteHost + "/edam/note/"; //$NON-NLS-1$ //$NON-NLS-2$

			userStoreTrans = new THttpClient(userStoreUrl);
			userStoreTrans.setCustomHeader("User-Agent", userAgent); //$NON-NLS-1$
			TBinaryProtocol userStoreProt = new TBinaryProtocol(userStoreTrans);
			userStore = new UserStore.Client(userStoreProt, userStoreProt);
			// Check that we can talk to the server
			boolean versionOk = userStore.checkVersion(
					"Evernote EDAMDemo (Java)", //$NON-NLS-1$
					com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR,
					com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);
			if (!versionOk) {
				System.err.println("Incomatible EDAM client protocol version"); //$NON-NLS-1$
				return false;
			}
			// Authenticate using username & password
			AuthenticationResult authResult = null;
			try {
				DBUserPass auth = properties.getAuthenticate();
				authResult = userStore.authenticate(auth.getUser(),
						auth.getPass(), DEF_CONSUMER_KEY, DEF_CONSUMER_SECRET);
			} catch (EDAMUserException ex) {
				String parameter = ex.getParameter();
				EDAMErrorCode errorCode = ex.getErrorCode();

				System.err.println("Authentication failed (parameter: " //$NON-NLS-1$
						+ parameter + " errorCode: " + errorCode + ")"); //$NON-NLS-1$ //$NON-NLS-2$

				if (errorCode == EDAMErrorCode.INVALID_AUTH) {
					if (parameter.equals("consumerKey")) { //$NON-NLS-1$
						if (DEF_CONSUMER_KEY.equals("en-edamtest")) { //$NON-NLS-1$
							System.err
									.println("You must replace the variables consumerKey and consumerSecret with the values you received from Evernote."); //$NON-NLS-1$
						} else {
							System.err
									.println("Your consumer key was not accepted by " //$NON-NLS-1$
											+ evernoteHost);
							System.err
									.println("This sample client application requires a client API key. If you requested a web service API key, you must authenticate using OAuth as shown in sample/java/oauth"); //$NON-NLS-1$
						}
						System.err
								.println("If you do not have an API Key from Evernote, you can request one from http://www.evernote.com/about/developer/api"); //$NON-NLS-1$
					} else if (parameter.equals("username")) { //$NON-NLS-1$
						System.err
								.println("You must authenticate using a username and password from " //$NON-NLS-1$
										+ evernoteHost);
						if (evernoteHost.equals("www.evernote.com") == false) { //$NON-NLS-1$
							System.err
									.println("Note that your production Evernote account will not work on " //$NON-NLS-1$
											+ evernoteHost + ","); //$NON-NLS-1$
							System.err
									.println("you must register for a separate test account at https://" //$NON-NLS-1$
											+ evernoteHost
											+ "/Registration.action"); //$NON-NLS-1$
						}
					} else if (parameter.equals("password")) { //$NON-NLS-1$
						System.err
								.println("The password that you entered is incorrect"); //$NON-NLS-1$
					}
				}

				return false;
			}
			authToken = authResult.getAuthenticationToken();

			loginUser = authResult.getUser();

			// Set up the NoteStore client
			getNoteStoreClient(loginUser.getShardId());
			// String noteStoreUrl = noteStoreUrlBase + shardId;
			// THttpClient noteStoreTrans = new THttpClient(noteStoreUrl);
			//			noteStoreTrans.setCustomHeader("User-Agent", userAgent); //$NON-NLS-1$
			// TBinaryProtocol noteStoreProt = new
			// TBinaryProtocol(noteStoreTrans);
			// noteStore = new NoteStore.Client(noteStoreProt, noteStoreProt);
			_info.setConnected(true);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return true;
	}

	@Override
	public boolean close() throws SQLException {
		_info.setConnected(false);
		return true;
	}

	public static String getHostString() {
		return www_evernoteHost;
	}

	@Override
	public void setTableColumns(String schema, IDBTable table)
			throws SQLException {
		EvernoteDBTable eTable = cast(table);
		for (IDBColumn col : eTable.getColumns()) {
			table.putResource(col.getName(), col);
		}
	}
}
