/*
 * This file is part of NixNote/NeighborNote 
 * Copyright 2009 Randy Baumgarte
 * 
 * This file may be licensed under the terms of of the
 * GNU General Public License Version 2 (the ``GPL'').
 *
 * Software distributed under the License is distributed
 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
 * express or implied. See the GPL for the specific language
 * governing rights and limitations.
 *
 * You should have received a copy of the GPL along with this
 * program. If not, go to http://www.gnu.org/licenses/gpl.html
 * or write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
*/

package cx.fbn.nevernote.utilities;

import java.io.File;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;

import com.evernote.edam.type.Data;
import com.evernote.edam.type.Note;
import com.evernote.edam.type.NoteAttributes;
import com.evernote.edam.type.Resource;
import com.evernote.edam.type.ResourceAttributes;
import com.trolltech.qt.core.QByteArray;
import com.trolltech.qt.core.QFile;
import com.trolltech.qt.core.QFileInfo;
import com.trolltech.qt.core.QIODevice;
import com.trolltech.qt.webkit.QWebPage;

import cx.fbn.nevernote.Global;
import cx.fbn.nevernote.NeverNote;
import cx.fbn.nevernote.sql.DatabaseConnection;



public class FileImporter  {

	private final ApplicationLogger	logger;
	private String				fileName;
	private String 				content;
	private QFileInfo 			fileInfo;
	private Note				newNote;
	private String				noteString;
	private final DatabaseConnection	conn;
	
	
	public FileImporter(ApplicationLogger l, DatabaseConnection c) {
		logger = l;
		conn = c;
	}
	
	
	//********************************************************
	//* Begin to import the file
	//********************************************************
	public boolean importFile() {
		if (fileInfo.isFile()) {
			if (fileInfo.completeSuffix().equalsIgnoreCase("txt"))
				return importTextFile();
			return importAttachment();
		}
		return false;
	}
	
	//********************************************************
	//* Import text files 
	//********************************************************
	public boolean importTextFile() {
		QFile file = new QFile(fileName);
		if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
			// If we can't get to the file, it is probably locked.  We'll try again later.
			logger.log(logger.LOW, "Unable to save externally edited file - locked.  Saving for later.");
			return false;
		}
		QByteArray binData = file.readAll();
		file.close();
		if (binData.size() == 0) {
			// If we can't get to the file, it is probably locked.  We'll try again later.
			logger.log(logger.LOW, "Unable to save externally edited file - zero size.  Saving for later.");
			return false;
		}
	
		String fileData =binData.toString();
		
		// Fix \r\n & \n and turn inte HTML
		QWebPage page = new QWebPage();
		page.mainFrame().setContent(binData);
		fileData = page.mainFrame().toHtml();
		fileData = fileData.replace("\n", "<br>\n");

		noteString = new String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
				"<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
				"<en-note>\n<br clear=\"none\" />"+fileData+"</en-note>");

		noteString = fileData;
		buildEmptyNote();
    	newNote.setAttributes(new NoteAttributes());
	    		
	    return true;
	}

	//********************************************************
	//* Import an image
	//********************************************************
	public boolean importAttachment() {
		QFile file = new QFile(fileName);
		if (!file.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly))) {
			// If we can't get to the file, it is probably locked.  We'll try again later.
			logger.log(logger.LOW, "Unable to save externally edited file - locked.  Saving for later.");
			return false;
		}
		QByteArray binData = file.readAll();
		file.close();
		if (binData.size() == 0) {
			// If we can't get to the file, it is probably locked.  We'll try again later.
			logger.log(logger.LOW, "Unable to save externally edited file - zero size.  Saving for later.");
			return false;
		}
			
		buildEmptyNote();
    	newNote.setAttributes(new NoteAttributes());
    
    	// Start building the resource itself
    	StringBuffer buffer = new StringBuffer();
    	buffer.append("<html><head></head><body>\n");
    	
    	Resource newRes;
    	
    	// If we have an image
    	if (isImage(fileInfo.completeSuffix())) {
        	String mimeType = "image/" +fileInfo.completeSuffix();
        	if (mimeType.equals("image/jpg"))
        		mimeType = "image/jpeg";
        	newRes = createResource(mimeType, false);
        	
    		buffer.append("<img src=\"" +fileName);
    		buffer.append("\" en-tag=\"en-media\" type=\"" + mimeType +"\""
    				+" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\""
    				+" guid=\"" +newRes.getGuid() +"\">");
    	} else {
    		// We have an attachment, not an image.
    		
    		
        	String mimeType = "application/" +fileInfo.completeSuffix();
        	newRes = createResource(mimeType, false);
        	newRes.getAttributes().setFileName(fileInfo.fileName());
    		
        	String icon = findIcon(fileInfo.completeSuffix());
		String imageURL = FileUtils.toFileURLString(Global.getFileManager().getImageDirFile(icon));
    		buffer.append("<a en-tag=\"en-media\" guid=\"" +newRes.getGuid()+"\" ");
			buffer.append("type=\"" + mimeType + "\" href=\"nnres://" + fileName +"\" hash=\""+Global.byteArrayToHexString(newRes.getData().getBodyHash()) +"\" >");
			buffer.append("<img src=\"" + imageURL +"\" title=\"" +newRes.getAttributes().getFileName());
			buffer.append("\">");
			buffer.append("</a>");
    	}
		buffer.append("</body></html>");
		
		content = buffer.toString();
		noteString = buffer.toString();
		newNote.setContent(content);
		newNote.setResources(new ArrayList<Resource>());
		newNote.getResources().add(newRes);
		newNote.setResourcesIsSet(true);
    	
    	return true;
	}
	
	
	//********************************************************
	//* Check if we found an image
	//********************************************************
	// Check if the account supports this type of attachment
	private boolean isImage(String type) {
		if (type.equalsIgnoreCase("JPG"))
			return true;
		if (type.equalsIgnoreCase("JPEG"))
			return true;
		if (type.equalsIgnoreCase("PNG"))
			return true;
		if (type.equalsIgnoreCase("GIF"))
			return true;
		if (!Global.isPremium()) 
			return false;
		if (type.equalsIgnoreCase("XPM"))
			return true;
		if (type.equalsIgnoreCase("BMP"))
			return true;

		return false;
	}

	//********************************************************
	//* Build an empty note
	//********************************************************
	private void buildEmptyNote() {
		Calendar currentTime = new GregorianCalendar();
		String baseNote = new String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
				"<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">\n" +
				"<en-note>\n<br clear=\"none\" /></en-note>");
		Long l = new Long(currentTime.getTimeInMillis());
		long prevTime = l;
		while (prevTime==l) {
			currentTime = new GregorianCalendar();
			l=currentTime.getTimeInMillis();
		}
		
		String randint = new String(Long.toString(l));
		
    	newNote = new Note();
    	newNote.setUpdateSequenceNum(0);
    	newNote.setGuid(randint);
    	newNote.setTitle(fileName);
    	newNote.setContent(baseNote);
    	newNote.setDeleted(0);
    	int cdate = fileInfo.created().toTime_t();
    	int mdate = fileInfo.lastModified().toTime_t();
    	newNote.setCreated((long)cdate*1000);
    	newNote.setUpdated((long)mdate*1000);
    	newNote.setActive(true);
    	NoteAttributes na = new NoteAttributes();
    	na.setLatitude(0.0);
    	na.setLongitude(0.0);
    	na.setAltitude(0.0);
	}
	//********************************************************
	//* Check valid file types
	//********************************************************
	public boolean isValidType() {
		if (!checkFileAttachmentSize(fileName))
			return false;
		return true;
	}
	//**************************************************************
	//* Check the file attachment to be sure it isn't over 25 mb
	//**************************************************************
	private boolean checkFileAttachmentSize(String url) {
		QFile resourceFile = new QFile(fileName);
		resourceFile.open(new QIODevice.OpenMode(
				QIODevice.OpenModeFlag.ReadOnly));
		long size = resourceFile.size();
		resourceFile.close();
		size = size / 1024 / 1024;
		if (size < 50 && Global.isPremium())
			return true;
		if (size < 25)
			return true;
		return false;
	}

	//********************************************************
	//* Build a new resource
	//********************************************************
	private Resource createResource(String mime, boolean attachment) {
		QFile resourceFile;
    	resourceFile = new QFile(fileName); 
    	resourceFile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.ReadOnly));
    	byte[] fileData = resourceFile.readAll().toByteArray();
    	resourceFile.close();
    	if (fileData.length == 0)
    		return null;
    	MessageDigest md;
    	try {
    		md = MessageDigest.getInstance("MD5");
    		md.update(fileData);
    		byte[] hash = md.digest();
  
    		Resource r = new Resource();
    		Calendar time = new GregorianCalendar();
    		Long l = time.getTimeInMillis();
    		long prevTime = l;
    		while (l==prevTime) {
    			time = new GregorianCalendar();
    			l=time.getTimeInMillis();
    		}
    		r.setGuid(new Long(l).toString());
    		r.setNoteGuid(newNote.getGuid());
    		r.setMime(mime);
    		r.setActive(true);
    		r.setUpdateSequenceNum(0);
    		r.setWidth((short) 0);
    		r.setHeight((short) 0);
    		r.setDuration((short) 0);
    		  		
    		Data d = new Data();
    		d.setBody(fileData);
    		d.setBodyIsSet(true);
    		d.setBodyHash(hash);
    		d.setBodyHashIsSet(true);
    		r.setData(d);
    		d.setSize(fileData.length);
    		
    		ResourceAttributes a = new ResourceAttributes();
    		a.setAltitude(0);
    		a.setAltitudeIsSet(false);
    		a.setLongitude(0);
    		a.setLongitudeIsSet(false);
    		a.setLatitude(0);
    		a.setLatitudeIsSet(false);
    		a.setCameraMake("");
    		a.setCameraMakeIsSet(false);
    		a.setCameraModel("");
    		a.setCameraModelIsSet(false);
    		a.setAttachment(attachment);
    		a.setAttachmentIsSet(true);
    		a.setClientWillIndex(false);
    		a.setClientWillIndexIsSet(true);
    		a.setRecoType("");
    		a.setRecoTypeIsSet(false);
    		a.setSourceURLIsSet(false);
    		a.setTimestamp(0);
    		a.setTimestampIsSet(false);
    		a.setFileName(fileInfo.fileName());
    		a.setFileNameIsSet(true);
    		r.setAttributes(a);
    		
    		conn.getNoteTable().noteResourceTable.saveNoteResource(r, true);
    		return r;
    	} catch (NoSuchAlgorithmException e1) {
    		e1.printStackTrace();
		}
    	return null;
	}
	
	//********************************************************
	//* set file name
	//********************************************************
	public void setFileInfo(QFileInfo f) {
		fileInfo = f;		
	}
	//********************************************************
	//* Set file name
	//********************************************************
	public void setFileName(String f) {
		fileName = f;
	}
	//********************************************************
	//* Get file contents
	//********************************************************
	public String getContent() {
		return content;
	}
	//********************************************************
	//* Return the new note
	//********************************************************
	public Note getNote() {
		return newNote;
	}
	//********************************************************
	//* Get just the content of the new note
	//********************************************************
	public String getNoteContent() {
		return noteString;
	}

    /**
     * find the appropriate icon for an attachment
     * NFC TODO: duplicate of {@link NeverNote#findIcon(String)}
     */
    private String findIcon(String appl) {
        appl = appl.toLowerCase();
        String relativePath = appl + ".png";
        File f = Global.getFileManager().getImageDirFile(relativePath);
        if (f.exists()) {
            return relativePath;
        }
        return "attachment.png";
    }

}
