package de.ugoe.cs.autoquest.androidmonitor;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;

import org.xmlpull.v1.XmlSerializer;

import android.util.Log;
import android.util.Xml;
import android.view.View;
import android.view.ViewGroup;

public class AndroidmonitorLogFile {

	// TODO rename getDeviceInformation() and getAppInformation() to set ... use
	// writeToFile for both

	private String name;
	private File file;

	public AndroidmonitorLogFile(String appName, File dir) {
		this.name = "android_" + appName + "_LogFile.xml";

		try {
			// prove if file exists
			this.file = new File(dir, this.name);
			/*
			 * if file does not exists write device and app information to a new
			 * file. Otherwise use existing file and add activity information to
			 * file.
			 */
			if (true) { // !this.file.exists()
				/*
				 * create log file. Using method openFileOutput() does not work
				 * for this project due to the reason that this method would try
				 * to create the file in the directory of the non-existing
				 * directory de.ugoe.cs.androidmonitor. This directory does not
				 * exist due to the reason that this project is a library and
				 * the file has to be stored in the directory of the running
				 * application. Furthermore it would not be possible to write in
				 * another app directory as the own one.
				 */

				// TODO split document head information from
				// getDeviceInformation.

				String string = "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><session>"
						+ getDeviceInformation() + getAppInformation();
				try {
					FileOutputStream outputStream = new FileOutputStream(
							this.file);
					outputStream.write(string.getBytes());
					outputStream.close();
				} catch (Exception e) {
					Log.e("this.file", "outputstream: " + e.getMessage());
				}

			} else {
				// TODO add activity information
			}
		} catch (Exception e) {
			e.printStackTrace();
			Log.e("file", "file: " + e.getMessage());
		}

	}

	/**
	 * get file name
	 * 
	 * @return
	 */
	public String getName() {
		return this.name;
	}

	// should be set
	private String getAppInformation() {
		// TODO create app information in the same manner as coded in
		// getDeviceInformation
		return "";
	}

	/**
	 * Query device information. XML format.
	 * 
	 * @return
	 */
	// should be set
	private String getDeviceInformation() {
		String deviceInformation = "";
		XmlSerializer serializer = Xml.newSerializer();
		StringWriter writer = new StringWriter();
		try {
			serializer.setOutput(writer);
			serializer.startTag("", "device");
			serializer.startTag("", "param");
			serializer.attribute("", "value", ""
					+ android.os.Build.VERSION.SDK_INT);
			serializer.attribute("", "name", "sdk_version");
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "value", android.os.Build.DEVICE);
			serializer.attribute("", "name", "device");
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "value", android.os.Build.MANUFACTURER);
			serializer.attribute("", "name", "manufacturer");
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "value", android.os.Build.MODEL);
			serializer.attribute("", "name", "model");
			serializer.endTag("", "param");

			// TODO get resolution ...

			serializer.endTag("", "device");
			serializer.endDocument();

			deviceInformation = writer.toString();

		} catch (IOException e) {
			Log.e("xml", e.getMessage());
		}

		return deviceInformation;
	}

	public void addComponent(View view, int parentHash, String activityName) {
		XmlSerializer serializer = Xml.newSerializer();
		StringWriter writer = new StringWriter();
		// create HEX string

		try {
			serializer.setOutput(writer);
			serializer.startTag("", "component");
			// TODO use hex string instead of integer number
			serializer.attribute("", "hash", "" + view.hashCode());

			serializer.startTag("", "param");
			serializer.attribute("", "name", "id");
			serializer.attribute("", "value", "" + view.getId());
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "name", "path");
			serializer.attribute("", "value", activityName + "/"
					+ getViewPath(view) + view.getClass().getSimpleName());
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "name", "class");
			serializer.attribute("", "value", view.getClass().getName());
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "name", "parent");
			// Problem in using view.getParent().hashCode():
			// http://developer.android.com/reference/android/view/View.html#getParent()
			// tells: "... parent is a ViewParent and not necessarily a View."
			// ViewParent does not have a method hashCode(). Solution is done
			// add parentHash as parameter to method addComponent() and
			// Androidmonitor-> addLogListenerToView.
			serializer.attribute("", "value", "" + parentHash);
			serializer.endTag("", "param");

			serializer.endTag("", "component");
			serializer.endDocument();

			writeToFile(writer.toString());

		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e("file", "outputstream: " + e.getMessage());
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e("file", "outputstream: " + e.getMessage());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e("file", "outputstream: " + e.getMessage());
		}

	}

	public void addEvent(View view) {

		String x = "" + view.getX();
		String y = "" + view.getY();

		XmlSerializer serializer = Xml.newSerializer();
		StringWriter writer = new StringWriter();

		try {
			serializer.setOutput(writer);

			serializer.startTag("", "event");
			serializer.attribute("", "type", view.getClass().getSimpleName());

			serializer.startTag("", "param");
			serializer.attribute("", "value", x);
			serializer.attribute("", "name", "X");
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "value", y);
			serializer.attribute("", "name", "Y");
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "value", "" + view.hashCode());
			serializer.attribute("", "name", "source");
			serializer.endTag("", "param");

			serializer.startTag("", "param");
			serializer.attribute("", "value", "" + System.currentTimeMillis());
			serializer.attribute("", "name", "timestamp");
			serializer.endTag("", "param");

			serializer.endTag("", "event");
			serializer.endDocument();

			writeToFile(writer.toString());
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e("file", "outputstream: " + e.getMessage());
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e("file", "outputstream: " + e.getMessage());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e("file", "outputstream: " + e.getMessage());
		}
	}

	private void writeToFile(String data) {

		FileOutputStream outputStream;
		try {
			outputStream = new FileOutputStream(file, true);
			outputStream.write(data.getBytes());
			outputStream.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			Log.e("file", "outputstream: " + e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			Log.e("file", "outputstream: " + e.getMessage());
		}

	}

	/**
	 * generates the path of an view element
	 * 
	 * @param view
	 * @return path to the element
	 */
	private String getViewPath(View view) {
		return getViewPath(view, null);
	}

	/**
	 * generates the path of an view element
	 * 
	 * @param view
	 * @param path
	 * @return path to the element
	 */
	private String getViewPath(View view, String path) {
		if (path == null) {
			path = "";
		} else {
			path = view.getClass().getSimpleName() + "/" + path;
		}
		if (view.getParent() != null && (view.getParent() instanceof ViewGroup)) {
			return getViewPath((View) view.getParent(), path);
		} else {
			return path;
		}
	}

}
