package com.yuji.ec.utility;

import java.net.ConnectException;
import java.util.ArrayList;
import java.util.List;

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

import android.content.Context;

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.NoteFilter;
import com.evernote.edam.notestore.NoteList;
import com.evernote.edam.notestore.NoteStore;
import com.evernote.edam.type.Note;
import com.evernote.edam.type.NoteSortOrder;
import com.evernote.edam.type.Notebook;
import com.evernote.edam.type.Tag;
import com.evernote.edam.type.User;
import com.evernote.edam.userstore.AuthenticationResult;
import com.evernote.edam.userstore.UserStore;
import com.yuji.ec.R;
import com.yuji.ec.db.INoteItem;

public class EvernoteUtil {
	private static final int N = 50;
	private String username;
	private String password;

	public enum Error {
		NONE, CONNECT, INVALID_AUTH, NOT_FOUND, OTHER
	};

	private Error errorCode;

	public static EvernoteUtil getInstance() {
		if (instance == null) {
			instance = new EvernoteUtil();
			instance.init();
		}
		return instance;
	}

	private static EvernoteUtil instance = null;

	private EvernoteUtil() {
		errorCode = Error.NONE;
	}

	private String authenticationToken = null;
	private NoteStore.Client noteStore = null;

	public void setConfig(String username, String password) {
		this.username = username;
		this.password = password;
		authenticationToken = null;
		noteStore = null;
	}

	private void init() {

	}

	public Note getNote(String guid) throws EDAMNotFoundException {
		boolean withContent = true;
		boolean withResourcesData = false;
		boolean withResourcesRecognition = false;
		boolean withResourcesAlternateData = false;
		Note note = null;
		errorCode = Error.OTHER;
		try {
			String token = getAuthenticationToken();
			if (token == null) {
				return null;
			}
			note = noteStore.getNote(token, guid, withContent,
					withResourcesData, withResourcesRecognition,
					withResourcesAlternateData);
			errorCode = Error.NONE;
		} catch (EDAMUserException e) {
			Debug.d(this, null, e);
		} catch (EDAMSystemException e) {
			Debug.d(this, null, e);
		} catch (EDAMNotFoundException e) {
			Debug.d(this, null, e);
			throw e;
		} catch (TException e) {
			Debug.d(this, null, e);

			if (e.getCause() instanceof ConnectException) {
				errorCode = Error.CONNECT;
			}
		}
		return note;
	}

	private NoteFilter getDefaultFilter(){
		// 検索条件として、検索語なし、更新日順ソートを指定
		NoteFilter filter = new NoteFilter();
		filter.setOrder(NoteSortOrder.UPDATED.getValue());
		filter.setAscending(false);		

		return filter;
	}
	
	public List<NoteList> getNoteList() {
		NoteFilter filter = getDefaultFilter();
		return getNoteList(filter);
	}

	public List<NoteList> getNoteListByNotebook(String notebookGuid) {
		NoteFilter filter = getDefaultFilter();
		filter.setNotebookGuid(notebookGuid);
		return getNoteList(filter);
	}
	
	public List<NoteList> getNoteListByTag(String tagGuid) {
		NoteFilter filter = getDefaultFilter();
		List<String> tagGuids = new ArrayList<String>();
		tagGuids.add(tagGuid);
		filter.setTagGuids(tagGuids);
		return getNoteList(filter);
	}
	
	public List<NoteList> getNoteList(NoteFilter filter) {
		errorCode = Error.OTHER;

		List<NoteList> list = new ArrayList<NoteList>();
		try {
			String token = getAuthenticationToken();
			if (token == null) {
				return null;
			}
			int index = 0;
			while (true){
				NoteList noteList = noteStore.findNotes(token, filter, index, N);
				int size = noteList.getNotesSize();
				
				if (size <= 0){
					break;
				}
				list.add(noteList);
				if (size < N){
					break;
				}
				index += size;
			}
			
			errorCode = Error.NONE;
		} catch (EDAMUserException e) {
			Debug.d(this, null, e);
			list = null;
		} catch (EDAMSystemException e) {
			Debug.d(this, null, e);
			list = null;
		} catch (EDAMNotFoundException e) {
			Debug.d(this, null, e);
			list = null;
		} catch (TException e) {
			Debug.d(this, null, e);

			if (e.getCause() instanceof ConnectException) {
				errorCode = Error.CONNECT;
			}
			list = null;
		}
		return list;
	}

	public List<Notebook> getNoteBookList() {
		errorCode = Error.OTHER;

		List<Notebook> noteBookList = null;
		try {
			String token = getAuthenticationToken();
			if (token == null) {
				return null;
			}
			noteBookList = noteStore.listNotebooks(token);
			errorCode = Error.NONE;
		} catch (EDAMUserException e) {
			Debug.d(this, null, e);
		} catch (EDAMSystemException e) {
			Debug.d(this, null, e);
		} catch (TException e) {
			Debug.d(this, null, e);

			if (e.getCause() instanceof ConnectException) {
				errorCode = Error.CONNECT;
			}
		}
		return noteBookList;
	}

	public List<Tag> getTagList() {
		errorCode = Error.OTHER;

		List<Tag> tagList = null;
		try {
			String token = getAuthenticationToken();
			if (token == null) {
				return null;
			}
			tagList = noteStore.listTags(token);
			errorCode = Error.NONE;
		} catch (EDAMUserException e) {
			Debug.d(this, null, e);
		} catch (EDAMSystemException e) {
			Debug.d(this, null, e);
		} catch (TException e) {
			Debug.d(this, null, e);

			if (e.getCause() instanceof ConnectException) {
				errorCode = Error.CONNECT;
			}
		}
		return tagList;
	}

	public Note updateNoteContext(String guid, String title, String text) {
		errorCode = Error.OTHER;

		Note note = null;
		try {
			note = getNote(guid);
		} catch (EDAMNotFoundException e) {
			errorCode = Error.NOT_FOUND;
		}
		if (note == null) {
			return null;
		}
		String content = note.getContent();

		// #27970
		// 見つからない場合
		String endTag = "</en-note>";
		int pos = content.indexOf(endTag);
		if (pos < 0) {
			return null;
		}
		StringBuffer sb = new StringBuffer();
		sb.append(content.substring(0, pos));
		if (title != null) {
			sb.append(title);
		}
		sb.append("<div>");
		sb.append(text);
		sb.append("</div>");
		sb.append(content.substring(pos));
		content = sb.toString();
		note.setContent(content);

		Note n = updateNote(note);

		errorCode = Error.NONE;
		return n;
	}

	public Note updateNote(Note note) {
		errorCode = Error.OTHER;
		Note n = null;
		try {
			String token = getAuthenticationToken();
			if (token == null) {
				return null;
			}
			n = noteStore.updateNote(token, note);
			errorCode = Error.NONE;
		} catch (EDAMUserException e) {
			Debug.d(this, null, e);
		} catch (EDAMSystemException e) {
			Debug.d(this, null, e);
		} catch (EDAMNotFoundException e) {
			e.printStackTrace();
		} catch (TException e) {
			Debug.d(this, null, e);

			if (e.getCause() instanceof ConnectException) {
				errorCode = Error.CONNECT;
			}
		}
		return n;
	}

	private String getAuthenticationToken() {
		try {
			if (authenticationToken == null) {
				// String userStoreUrl =
				// "https://sandbox.evernote.com/edam/user";
				String userStoreUrl = "https://www.evernote.com/edam/user";
				THttpClient userStoreTrans = new THttpClient(userStoreUrl);
				TBinaryProtocol userStoreProt = new TBinaryProtocol(
						userStoreTrans);
				UserStore.Client userStore = new UserStore.Client(userStoreProt);

				// #27612
				// http://www.antun.net/tips/api/evernote.html
				// expiredTime=time.time()+(authResult.expiration/1000.0-authResult.currentTime/1000.0)
				// # expiredTime<time.time() なら認証し直して、authenticationToken
				// を取得し直すべし

				String consumerKey = "yuji_k64613";
				String consumerSecret = "d5528b4fdb3a7fee";
				AuthenticationResult authResult = userStore.authenticate(
						username, password, consumerKey, consumerSecret);
				authenticationToken = authResult.getAuthenticationToken();

				// String noteStoreUrlBase =
				// "https://sandbox.evernote.com/edam/note/";
				String noteStoreUrlBase = "https://www.evernote.com/edam/note/";
				User user = authResult.getUser();
				String noteStoreUrl = noteStoreUrlBase + user.getShardId();
				THttpClient noteStoreTrans = new THttpClient(noteStoreUrl);
				TBinaryProtocol noteStoreProt = new TBinaryProtocol(
						noteStoreTrans);
				noteStore = new NoteStore.Client(noteStoreProt);
			}
		} catch (TTransportException e) {
			authenticationToken = null;
			noteStore = null;
			Debug.d(this, null, e);

			errorCode = Error.CONNECT;
		} catch (EDAMUserException e) {
			Debug.d(this, null, e);

			EDAMErrorCode code = e.getErrorCode();
			if (code.equals(EDAMErrorCode.INVALID_AUTH)) {
				errorCode = Error.INVALID_AUTH;
			}
		} catch (EDAMSystemException e) {
			Debug.d(this, null, e);
		} catch (TException e) {
			Debug.d(this, null, e);

			if (e.getCause() instanceof ConnectException) {
				errorCode = Error.CONNECT;
			}
		}

		return authenticationToken;
	}

	public Error getErrorCode() {
		return errorCode;
	}

	public String getErrorMessage(Context context, Error code) {
		if (code.equals(Error.NONE)) {
			return "";
		}
		if (code.equals(Error.CONNECT)) {
			return context.getString(R.string.toastConnect);
		}
		if (code.equals(Error.INVALID_AUTH)) {
			return context.getString(R.string.toastInvalidAuth);
		}
		if (code.equals(Error.NOT_FOUND)) {
			return context.getString(R.string.toastNoteDoesNotExist);
		}
		return context.getString(R.string.toastEvernoteSystem);
	}

	public static com.yuji.ec.db.Note toNote(Note n, String text) {
		com.yuji.ec.db.Note note = new com.yuji.ec.db.Note(n.getGuid(), text,
				n.getCreated(), n.getUpdated());
		return note;
	}

	public List<com.yuji.ec.db.Note> getNoteContentList(List<NoteList> noteListList) {
		List<com.yuji.ec.db.Note> list = new ArrayList<com.yuji.ec.db.Note>();
		for (NoteList noteList : noteListList){
			List<com.yuji.ec.db.Note> l = getNoteContentList(noteList);
			if (l == null){
				return null;
			}
			list.addAll(l);
		}
		return list;
	}
	
	public List<com.yuji.ec.db.Note> getNoteContentList(NoteList noteList) {
		errorCode = Error.OTHER;

		List<com.yuji.ec.db.Note> list = new ArrayList<com.yuji.ec.db.Note>();
		HtmlParser parser = new HtmlParser();

		try {
			List<Note> notes = noteList.getNotes();
			int s = noteList.getNotesSize();
			System.out.println("" + s);
			for (Note n : notes) {
				String guid = n.getGuid();
				Note nc = getNote(guid);
				String content = nc.getContent();
				if (!parser.parse(content)){
					return null;
				}
				String text = parser.getText();
				com.yuji.ec.db.Note note = toNote(nc, text);
				list.add(note);
			}
			notes = noteList.getNotes();
			s = noteList.getNotesSize();
			errorCode = Error.NONE;
		} catch (EDAMNotFoundException e) {
			errorCode = Error.NOT_FOUND;
			return null;
		}
		return list;
	}

	public List<INoteItem> toNoteItemFromNoteBook(List<Notebook> noteList) {
		List<INoteItem> list = new ArrayList<INoteItem>();
		for (Notebook notebook : noteList) {
			com.yuji.ec.db.Note item = new com.yuji.ec.db.Note(
					notebook.getGuid(), notebook.getName(), -1, -1);
			list.add(item);
		}
		return list;
	}

	public List<INoteItem> toNoteItemFromTag(List<Tag> tagList) {
		List<INoteItem> list = new ArrayList<INoteItem>();
		for (Tag tag : tagList) {
			com.yuji.ec.db.Note item = new com.yuji.ec.db.Note(tag.getGuid(),
					tag.getName(), -1, -1);
			list.add(item);
		}
		return list;
	}

}
