package filemanager;

import com.one.Directory;
import com.one.ErrScreen;
import com.one.FileInputStream;
import com.one.FileSystemObject;
import com.one.IniRecord;
import com.one.PaintableObject;
import com.one.RandomAccessInputStream;
import com.one.Renderer;
import com.one.TextProcessor;
import com.one.file.Connector;
import com.one.file.FileConnection;
import com.vmx.AuxClass;
import com.vmx.BufDataInputStream;
import com.vmx.InputStreamDecoder;
import com.vmx.Locale;
import com.vmx.OutputStreamEncoder;
import com.vmx.StringEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.rms.RecordStore;

public class TemplateManager implements CommandListener
{
	protected static final String ITEM_START = "<p_item>";
	protected static final String ITEM_END = "</p_item>";
	protected static final String RECORD_START = "<p_record>";
	protected static final String RECORD_END = "</p_record>";

	protected static Hashtable templates;		// содержимое шаблонов по именам
	protected static Hashtable directory;		// каталог шаблонов (с папками)
	
	protected static ListMenu list;
	protected static String currpath = "";
	protected static Object target;
	protected static Object parent;

	protected static Form form;
	protected static TextField tfName;
	protected static TextField tfText;

	protected static TextBox tbFolderName;
	protected static boolean createNew;

	protected static Command cmdOK;
	protected static Command cmdAdd;
	protected static Command cmdNewFolder;
	protected static Command cmdEdit;
	protected static Command cmdDelete;
	protected static Command cmdBack;
	protected static Command cmdCancel;

	public static void loadTemplates()
	{
		if(templates == null)
		{
			templates = new Hashtable();
			directory = new Hashtable();
		}
		else
		{
			templates.clear();
			directory.clear();
		}

		try
		{
			RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(9), true);

			if(rs.getNumRecords() == 0)
			{
				rs.closeRecordStore();

				InputStreamDecoder ini = InputStreamDecoder.getResourceDecoder("/temp/template.ini");
				IniRecord record = null;

				InputStreamDecoder isd;
				StringBuffer text;

				while((record = IniRecord.getNextRecord(ini)) != null)
				{
					try
					{
						isd = InputStreamDecoder.getResourceDecoder("/temp/" + record.value + ".txt");
						text = new StringBuffer(isd.available());

						while(isd.available() > 0)
						{
							text.append(isd.readChar());
						}

						isd.close();

						addTemplate(record.key, text.toString());
					}
					catch(Throwable t)
					{
						System.out.println(t.toString() + " when loading " + record.key);
					}
				}

				ini.close();

				return;
			}

			DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(1)));
			rs.closeRecordStore();

			int count = dis.readInt();

			for(int i = 0; i < count; i++)
			{
				addTemplate(dis.readUTF(), dis.readUTF());
			}

			dis.close();
		}
		catch(Exception e)
		{
			ErrScreen.showErrMsg(89, e);
		}
	}

	public static void saveTemplates()
	{
		if(templates == null)
		{
			return;
		}

		try
		{
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			DataOutputStream dos = new DataOutputStream(baos);

			dos.writeInt(templates.size());

			Enumeration tempnames = templates.keys();
			String tempname;

			while(tempnames.hasMoreElements())
			{
				tempname = (String)tempnames.nextElement();

				dos.writeUTF(tempname);
				dos.writeUTF(getTemplate(tempname));
			}

			byte[] data = baos.toByteArray();
			dos.close();

			RecordStore rs = RecordStore.openRecordStore(AuxClass.getStoreName(9), true);

			if(rs.getNumRecords() == 0)
			{
				rs.addRecord(data, 0, data.length);
			}
			else
			{
				rs.setRecord(1, data, 0, data.length);
			}

			rs.closeRecordStore();
		}
		catch(Exception e)
		{
			ErrScreen.showErrMsg(139, e);
		}
	}

	public static void exportTemplates(String filename) throws IOException
	{
		if(templates == null)
		{
			loadTemplates();
		}

		FileConnection fc = (FileConnection)Connector.open("file:///" + filename);

		if(fc.exists())
		{
			fc.truncate(0);
		}
		else
		{
			fc.create();
		}

		OutputStreamEncoder ose = new OutputStreamEncoder(fc.openOutputStream(), StringEncoder.ENC_UTF8);
		ose.writeBOM();

		Enumeration tempnames = FileSystemObject.sortFileList(templates.keys());
		String tempname;

		while(tempnames.hasMoreElements())
		{
			tempname = (String)tempnames.nextElement();

			ose.writeString(tempname);
			ose.writeString("\t=\t");
			ose.writeString(TextProcessor.escapeString(getTemplate(tempname), StringEncoder.ENC_UTF8));
			ose.writeString("\r\n");
		}

		ose.close();
		fc.close();
	}

	public static void importTemplates(String filename) throws IOException
	{
		FileConnection fc = (FileConnection)Connector.open("file:///" + filename, Connector.READ);

		InputStreamDecoder isd = InputStreamDecoder.getFileDecoder(fc);
		IniRecord record;

		while((record = IniRecord.getNextRecord(isd)) != null)
		{
			addTemplate(record.key, TextProcessor.unescapeString(record.value));
		}

		isd.close();
		fc.close();
	}

	public static void importOperaMiniTemplates(String filename) throws IOException
	{
		FileConnection fc = (FileConnection)Connector.open("file:///" + filename, Connector.READ);

		RandomAccessInputStream rais = new FileInputStream(fc);
		BufDataInputStream bdis = new BufDataInputStream(rais);
		InputStreamDecoder isd = new InputStreamDecoder(bdis, StringEncoder.ENC_UTF8, 0);

		StringBuffer buf = new StringBuffer();

		try
		{
			while(true)
			{
				buf.append(isd.readChar());
			}
		}
		catch(EOFException eof)
		{
		}

		isd.close();
		isd = null;
		bdis = null;
		rais = null;

		fc.close();
		fc = null;

		String temp = buf.toString();
		buf = null;

		String[] record = new String[4];

		int istart, iend;
		int rstart, rend;

		int islen = ITEM_START.length();
		int rslen = RECORD_START.length();

		iend = 0;

		while(true)
		{
			istart = temp.indexOf(ITEM_START, iend) + islen;

			if(istart < islen)
			{
				break;
			}

			iend = temp.indexOf(ITEM_END, istart);
			rend = istart;

			for(int i = 0; i < 4; i++)
			{
				rstart = temp.indexOf(RECORD_START, rend) + rslen;
				rend = temp.indexOf(RECORD_END, rstart);

				record[i] = temp.substring(rstart, rend);
			}

			if(record[3].equals("0"))
			{
				addTemplate(record[0].substring(1) + record[1], record[2]);
			}
		}
	}

	public static void addTemplate(String name, String text)
	{
		if(templates == null)
		{
			loadTemplates();
		}

		templates.put(name, text);
		Directory.addFile(directory, name);
	}

	public static void deleteTemplate(String name)
	{
		if(templates == null)
		{
			loadTemplates();
		}

		templates.remove(name);
		Directory.deleteFile(directory, name);
	}

	public static void renameTemplate(String oldName, String newName)
	{
		if(templates == null)
		{
			loadTemplates();
		}

		String text = (String)templates.get(oldName);

		if(text != null)
		{
			deleteTemplate(oldName);
			addTemplate(newName, text);
		}
	}

	public static void addFolder(String name)
	{
		if(templates == null)
		{
			loadTemplates();
		}

		Directory.addFile(directory, name);
	}

	public static void deleteFolder(String folder)
	{
		if(templates == null)
		{
			loadTemplates();
		}

		Enumeration names = templates.keys();
		String name;

		while(names.hasMoreElements())
		{
			name = (String)names.nextElement();

			if(name.startsWith(folder))
			{
				deleteTemplate(name);
			}
		}

		Directory.deleteFile(directory, folder);
	}

	public static void renameFolder(String oldName, String newName)
	{
		if(templates == null)
		{
			loadTemplates();
		}

		Enumeration names = templates.keys();
		String name;

		int index = oldName.length();

		while(names.hasMoreElements())
		{
			name = (String)names.nextElement();

			if(name.startsWith(oldName))
			{
				renameTemplate(name, newName + name.substring(index));
			}
		}

		Directory.deleteFile(directory, oldName);
	}

	public static Enumeration listTemplates(String path)
	{
		if(templates == null)
		{
			loadTemplates();
		}

		return FileSystemObject.sortFileList(Directory.listFiles(directory, path));
	}

	public static String getTemplate(String name)
	{
		if(templates == null)
		{
			loadTemplates();
		}

		return (String)templates.get(name);
	}

	public static void showTemplateList(Object target, Object parent)
	{
		if(parent == null)
		{
			parent = main.dsp.getCurrent();
		}

		if(target instanceof TextField ||
		   target instanceof TextBox)
		{
			TemplateManager.target = target;
			TemplateManager.parent = parent;

			createUI();
			main.dsp.setCurrent(list);
		}
		else
		{
			throw new IllegalArgumentException("\"" + target + "\" is not an acceptable target");
		}
	}

	public static void createUI()
	{
		if(list != null)
		{
			return;
		}

		Object object = TemplateManager.class.getName();
		CommandListener cl = new TemplateManager();

		list = new ListMenu();
		list.setTitle(Locale.getString(object, Locale.TEMPLATES_CMD));

		cmdOK = new Command(Locale.getString(object, Locale.OK_CMD), Command.OK, 1);
		cmdAdd = new Command(Locale.getString(object, Locale.ADD_CMD), Command.OK, 2);
		cmdNewFolder = new Command(Locale.getString(object, Locale.CREATE_NEW_FOLDER), Command.OK, 3);
		cmdEdit = new Command(Locale.getString(object, Locale.EDIT_CMD), Command.OK, 4);
		cmdDelete = new Command(Locale.getString(object, Locale.DELETE_CMD), Command.OK, 5);
		cmdBack = new Command(Locale.getString(object, Locale.BACK_CMD), Command.BACK, 6);
		cmdCancel = new Command(Locale.getString(object, Locale.CANCEL_CMD), Command.CANCEL, 7);

		list.addCommand(cmdAdd);
		list.addCommand(cmdNewFolder);
		list.addCommand(cmdBack);
		list.addCommand(cmdCancel);
		list.setCommandListener(cl);

		form = new Form(Locale.getString(object, Locale.EDIT_CMD));

		tfName = new TextField(Locale.getString(object, Locale.NAME), "", 256, TextField.ANY);
		tfText = new TextField(Locale.getString(object, Locale.TEXT), "", 8192, TextField.ANY);

		form.append(tfName);
		form.append(tfText);

		form.addCommand(cmdOK);
		form.addCommand(cmdCancel);
		form.setCommandListener(cl);

		tbFolderName = new TextBox(Locale.getString(object, Locale.FOLDER_NAME), "", 256, TextField.ANY);

		tbFolderName.addCommand(cmdOK);
		tbFolderName.addCommand(cmdCancel);
		tbFolderName.setCommandListener(cl);

		updateList();
	}

	public static void updateList()
	{
		if(templates == null)
		{
			loadTemplates();
		}

		if(currpath.length() > 0)
		{
			list.setSubTitle(currpath, true);
		}
		else
		{
			list.setSubTitle(Locale.getString(TemplateManager.class.getName(), Locale.ROOT), false);
		}
		
		list.deleteAll();
		list.append(listTemplates(currpath));

		if(list.size() > 0)
		{
			list.addCommand(cmdOK);
			list.addCommand(cmdEdit);
			list.addCommand(cmdDelete);
		}
		else
		{
			list.removeCommand(cmdOK);
			list.removeCommand(cmdEdit);
			list.removeCommand(cmdDelete);
		}
	}

	public void commandAction(Command c, Displayable dp)
	{
		if(dp instanceof Renderer)
		{
			PaintableObject po = ((Renderer)dp).getCurrent();

			if(po == list)
			{
				if(c == cmdOK)
				{
					String s = list.getString(list.getSelectedIndex());

					if(s.endsWith("/"))
					{
						currpath += s;
						updateList();
					}
					else
					{
						if(target instanceof TextField)
						{
							TextField t = (TextField)target;
							t.setString(t.getString().substring(0, t.getCaretPosition()) + getTemplate(currpath + s) + t.getString().substring(t.getCaretPosition()));
						}
						else if(target instanceof TextBox)
						{
							TextBox t = (TextBox)target;
							t.setString(t.getString().substring(0, t.getCaretPosition()) + getTemplate(currpath + s) + t.getString().substring(t.getCaretPosition()));
						}
						else
						{
							throw new RuntimeException("Internal error: invalid target");
						}

						main.dsp.setCurrent(parent);
					}
				}
				else if(c == cmdAdd)
				{
					tfName.setString(AuxClass.timeToFileName(-1));
					tfText.setString("");

					main.dsp.setCurrent(form);
				}
				else if(c == cmdEdit)
				{
					String name = list.getString(list.getSelectedIndex());

					if(name.endsWith("/"))
					{
						tbFolderName.setString(name.substring(0, name.length() - 1));
						createNew = false;

						main.dsp.setCurrent(tbFolderName);
					}
					else
					{
						tfName.setString(name);
						tfText.setString(getTemplate(currpath + name));

						main.dsp.setCurrent(form);
					}
				}
				else if(c == cmdDelete)
				{
					String name = currpath + list.getString(list.getSelectedIndex());

					if(name.endsWith("/"))
					{
						deleteFolder(name);
					}
					else
					{
						deleteTemplate(name);
					}

					updateList();
				}
				else if(c == cmdNewFolder)
				{
					tbFolderName.setString(AuxClass.timeToFileName(-1));
					createNew = true;

					main.dsp.setCurrent(tbFolderName);
				}
				else if(c == cmdBack)
				{
					int index = currpath.lastIndexOf('/', currpath.length() - 2);

					if(index >= 0)
					{
						currpath = currpath.substring(0, index + 1);
					}
					else
					{
						currpath = "";
					}

					updateList();
				}
				else if(c == cmdCancel)
				{
					main.dsp.setCurrent(parent);
				}
			}
		}
		else if(dp == form)
		{
			if(c == cmdOK)
			{
				if(tfName.getString().length() == 0)
				{
					return;
				}

				deleteTemplate(currpath + tfName.getString());
				addTemplate(currpath + tfName.getString(), tfText.getString());

				updateList();
			}

			main.dsp.setCurrent(list);
		}
		else if(dp == tbFolderName)
		{
			if(c == cmdOK)
			{
				if(tbFolderName.getString().length() == 0)
				{
					return;
				}

				if(createNew)
				{
					addFolder(currpath + AuxClass.validateFileName(tbFolderName.getString()) + "/");
				}
				else
				{
					renameFolder(currpath + list.getString(list.getSelectedIndex()), currpath + AuxClass.validateFileName(tbFolderName.getString()) + "/");
				}

				updateList();
			}

			main.dsp.setCurrent(list);
		}
	}
}