package authoritymanager.server;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import tools.Authority;
import tools.UserLogin;


import authoritymanager.client.ClientConfiguration;
import authoritymanager.client.DataSerial;
import authoritymanager.client.GreetingService;
import authoritymanager.client.DataPair;
import authoritymanager.client.Record;
import authoritymanager.client.SearchQuery;
import authoritymanager.client.SearchResults;
import authoritymanager.client.Utilities;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class GreetingServiceImpl extends RemoteServiceServlet implements
		GreetingService {
	// private static String PATH = "/var/lib/tomcat6/webapps/ROOT/data/" ;
	private static String PATH = ".\\data\\";
	// public final String PATH = super.getInitParameter("root") ;
	// public final String PATH = "./data/" ;
	public final String LOGIN_FILE = PATH + "login.xml";

	private boolean initialized = false;

	public Authority authorityPersons, authorityMovies, authorityCorporates;
	int idxPersons, idxMovies;
	public Vector<DataPair> duplicatePersons, duplicateMovies;
	public Vector<UserLogin> users = new Vector<UserLogin>();

	@Override
	public void init_server() {
		if (!initialized) {
			// System.out.println("GWTO module base: " + GWT.getModuleBaseURL())
			// ;

			initialized = true;
			initUsers();
			// authorityPersons = TestModule.createAuthority("DIF-persons.conf",
			// "exp/dif-agent-p-", 326) ;
			// authorityMovies = TestModule.createAuthority("DIF-movies.conf",
			// "dif/dif_fw", 486) ;
			authorityPersons = new Authority(PATH + "\\" + "EFG-persons.conf") ;
			authorityMovies = new Authority(PATH + "\\" + "EFG-movies.conf") ;
			authorityCorporates = new Authority(PATH + "\\" + "EFG-corporates.conf") ;
			
			
//			duplicateMovies = getDuplicates(PATH + "movies-duplicates.txt");
	//		duplicatePersons = getDuplicates(PATH + "persons-duplicates.txt");
		}
	}

	private void initUsers() {
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(LOGIN_FILE);
			NodeList login = doc.getDocumentElement().getElementsByTagName(
					"user");
			for (int iNode = 0; iNode < login.getLength(); iNode++) {
				Node node = login.item(iNode);
				if (node.getNodeType() == Element.ELEMENT_NODE) {
					UserLogin userLogin = new UserLogin((Element) node);
					users.add(userLogin);
				}
			}
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private Vector<DataPair> getDuplicates(String fileName) {
		try {
			BufferedReader in = new BufferedReader(new FileReader(new File(
					fileName)));

			String line;
			Vector<DataPair> results = new Vector<DataPair>();
			try {
				while ((line = in.readLine()) != null) {
					DataPair pair = new DataPair();
					DataSerial first = new DataSerial();
					double distance = Double.parseDouble(line);
					String fieldName, fieldValue;
					line = in.readLine();
					line = in.readLine();
					while (!line.equals("$")) {
						StringTokenizer st = new StringTokenizer(line, "\t");
						if (st.hasMoreTokens()) {
							fieldName = st.nextToken();
							if (st.hasMoreTokens())
								fieldValue = st.nextToken();
							else
								fieldValue = "";
							first.put(fieldName, fieldValue);
						}
						line = in.readLine();
					}
					DataSerial second = new DataSerial();
					line = in.readLine();
					while (!line.equals("$")) {
						StringTokenizer st = new StringTokenizer(line, "\t");
						if (st.hasMoreTokens()) {
							fieldName = st.nextToken();
							if (st.hasMoreTokens())
								fieldValue = st.nextToken();
							else
								fieldValue = "";
							second.put(fieldName, fieldValue);
						}
						line = in.readLine();
					}
					pair.addData(distance, first, second);
					results.add(pair);

					line = in.readLine();
				}
				idxPersons = 0;
				idxMovies = 0;
				return results;
			} catch (IOException e) {
				e.printStackTrace();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

	
	@Override
	public DataPair nextPair(String type) {
		DataPair result = null;
		if (type.trim().equals(ClientConfiguration.MOVIE_TAG)) {
			idxMovies++;
			if (idxMovies == duplicateMovies.size())
				idxMovies = 0;
			result = duplicateMovies.get(idxMovies);
		}
		if (type.trim().equals(ClientConfiguration.PERSON_TAG)) {
			idxPersons++;
			if (idxPersons == duplicatePersons.size())
				idxPersons = 0;
			result = duplicatePersons.get(idxPersons);
		}
		return result;
	}

	@Override
	public DataPair prevPair(String type) {
		DataPair result = null;
		if (type.trim().equals(ClientConfiguration.MOVIE_TAG)) {
			idxMovies--;
			if (idxMovies < 0)
				idxMovies = duplicateMovies.size() - 1;
			result = duplicateMovies.get(idxMovies);
		}
		if (type.trim().equals(ClientConfiguration.PERSON_TAG)) {
			idxPersons--;
			if (idxPersons < 0)
				idxPersons = duplicatePersons.size() - 1;
			result = duplicatePersons.get(idxPersons);
		}
		return result;
	}

	@Override
	public void uploadFile() {
		System.out.println("0");
		HttpServletRequest request = super.getThreadLocalRequest();
		HttpServletResponse response = super.getThreadLocalResponse();
		System.out.println("1");
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		List<FileItem> items;
		FileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload upload = new ServletFileUpload();
		System.out.println("2");
		try {
			items = upload.parseRequest(request);
			for (FileItem item : items) {
				System.out.println("item = " + item);
			}
		} catch (Exception e) {

		}
		// List items = null;
		String text = "not loaded!";

		if (isMultipart) {
			// Create a factory for disk-based file items
			// FileItemFactory factory = new DiskFileItemFactory();

			// Create a new file upload handler
			// ServletFileUpload upload = new ServletFileUpload(factory);

			// Parse the request
			try {
				// items = upload.parseRequest(request);
				// <===========================I get the exception here
			} catch (Exception e) {
				text = e.getStackTrace().toString();
			}
		}
	}

	@Override
	public void upload() {
		// TODO Auto-generated method stub

	}

	@Override
	public void fileUpload() {
		// TODO Auto-generated method stub

	}

	@Override
	public String getConfiguration() {
		/*
		 * try {
		 * 
		 * System.out.println("GetConfiguration"); JAXBContext jaxbContext =
		 * JAXBContext.newInstance("eu.europeanfilmgateway.efg"); Marshaller
		 * marshaller = jaxbContext.createMarshaller(); Unmarshaller
		 * unmarshaller = jaxbContext.createUnmarshaller(); ObjectFactory
		 * factory = new ObjectFactory();
		 * 
		 * Avcreation avCreation = factory.createAvcreation();
		 * 
		 * IdentifierType identifierType = factory.createIdentifierType();
		 * identifierType.setValue("dsfsD");
		 * avCreation.setIdentifier(identifierType);
		 * 
		 * IdentifyingType title = factory.createIdentifyingType();
		 * title.setLang("German"); avCreation.setIdentifyingTitle(title);
		 * 
		 * marshaller.marshal(avCreation, new File("test.xml"));
		 * 
		 * } catch (JAXBException e) { e.printStackTrace(); }
		 */
		DocumentBuilderFactory docFactory = DocumentBuilderFactory
				.newInstance();
		try {
			Document doc = docFactory.newDocumentBuilder().parse(
					new File(PATH + "efg.xsd"));
			doc.getDocumentElement().normalize();
			StringWriter writer = new StringWriter();
			Transformer transformer = TransformerFactory.newInstance()
					.newTransformer();
			transformer.transform(new DOMSource(doc), new StreamResult(writer));
			return writer.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerFactoryConfigurationError e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
		return null;
	}

	public String getStatus() {
		return getXML("status.xml");
	}

	public String getXML(String fileName) {
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory
					.newInstance();
			Document doc = docFactory.newDocumentBuilder().parse(
					new File(PATH + fileName));
			doc.getDocumentElement().normalize();
			StringWriter writer = new StringWriter();
			Transformer transformer = TransformerFactory.newInstance()
					.newTransformer();
			transformer.transform(new DOMSource(doc), new StreamResult(writer));
			return writer.toString();

		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerFactoryConfigurationError e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public void insert(String choice, String query) {
		System.out.println("Inserting: " + query);
		if (choice.equals(ClientConfiguration.MOVIE_TAG)) {
			String[] st = query.split("$");
			for (int i = 0; i < st.length; i++) {
				String[] fields = st[i].split(":");
				System.out.println(fields[0] + ":" + fields[1]);
			}
		}
		if (choice.equals(ClientConfiguration.PERSON_TAG)) {

		}
		if (choice.equals(ClientConfiguration.CORPORATION_TAG)) {

		}

	}

	@Override
	public boolean login(String username, String date, String password) {
		for (Iterator<UserLogin> it = users.iterator(); it.hasNext();) {
			UserLogin user = it.next();
			if (user.username.equals(username)) {
				// return BCrypt.checkpw(password, user.password) ;
				return password.equals(user.password);
			}
		}
		return false;
	}

	public void dumpUsers() {
		String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + "\n\n";

		xml += "<login>";
		for (Iterator<UserLogin> it = users.iterator(); it.hasNext();) {
			UserLogin user = it.next();
			xml += user.toXML();
		}
		xml += "</login>";

		try {
			PrintWriter writer = new PrintWriter(LOGIN_FILE);
			writer.println(xml);
			writer.flush();
			writer.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public boolean register(String username, String password, String access) {
		for (Iterator<UserLogin> it = users.iterator(); it.hasNext();) {
			UserLogin user = it.next();
			if (user.username.equals(username)) {
				return false;
			} else {
				users.add(new UserLogin(username, password, access));
				dumpUsers();
				return true;
			}
		}
		users.add(new UserLogin(username, password, access));
		dumpUsers();
		return true;
	}

	@Override
	public String getPath() {
		File f = new File(PATH + "test.txt");
		String absPath = f.getAbsolutePath();
		System.out.println(absPath);
		String relPath = f.getPath();
		System.out.println(relPath);
		f.deleteOnExit();
		return absPath + "$" + relPath;
	}

	
	@Override
	public SearchResults search(String query) {
		System.out.println("Searching ..." + query) ;
		init_server();
		String searchType = query.substring(0, query.indexOf(Utilities.DELIMITER));
		query = query.substring(query.indexOf(Utilities.DELIMITER) + 1);

		if (searchType.equals(ClientConfiguration.MOVIE_TAG)) {
			return new SearchResults(searchType, authorityMovies.search(query));
		}
		if (searchType.equals(ClientConfiguration.PERSON_TAG)) {
			return new SearchResults(searchType, authorityPersons.search(query));
		}
		return null ;
		
	}

	@Override
	public SearchResults search(SearchQuery searchQuery) {
		System.out.println("Searching ..." + searchQuery) ;
		init_server();
		String searchType = searchQuery.getType() ;
		
		if (searchType.equals(ClientConfiguration.MOVIE_TAG)) {
			return new SearchResults(searchType, authorityMovies.search(searchQuery));
		}
		if (searchType.equals(ClientConfiguration.PERSON_TAG)) {
			return new SearchResults(searchType, authorityPersons.search(searchQuery));
		}
		return null ;
	}

	@Override
	public boolean addRecord(Record record) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void merge(DataPair winner, DataPair loser) {
		// TODO Auto-generated method stub
		
	}

	
	@Override
	public void setDifferent(DataPair data) {
		// TODO Auto-generated method stub
		
	}

}
