package org.ourfilesystem.simpleui;

/*
OurFileSystem is a peer2peer file sharing program.
Copyright (C) 2012  Robert Gass

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

*/

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.WindowConstants;
import javax.swing.table.AbstractTableModel;

import org.ourfilesystem.db.LocalPost;
import org.ourfilesystem.db.Post;
import org.ourfilesystem.filehander.FileHandler;
import org.ourfilesystem.postcodec.Codec;
import org.ourfilesystem.postcodec.PostDecoded;

import net.miginfocom.swing.MigLayout;
import javax.swing.JButton;

public class NewExpandedPostDialog extends JDialog {
	private static final long serialVersionUID = 1L;

	private final JPanel contentPanel = new JPanel();
	
	private class ReferencesTableModel extends AbstractTableModel {
		private static final long serialVersionUID = 1L;
		public LinkedList<PostDecoded> List;
		public ReferencesTableModel() {
			List = new LinkedList<PostDecoded>();
		}
		public void addNew(PostDecoded pd) {
			List.add(pd);
			fireTableDataChanged();
		}
		public void clear() {
			List.clear();
			fireTableDataChanged();
		}
		@Override
		public String getColumnName(int col) {
			if (col == 0) {
				return "File Name";
			}
			if (col == 1) {
				return "Digest";
			}
			return null;
		}
		
		@Override
		public int getColumnCount() {
			return 2;
		}

		@Override
		public int getRowCount() {
			return List.size();
		}

		@Override
		public Object getValueAt(int arg0, int arg1) {
			PostDecoded pd = List.get(arg0);
			if (arg1 == 0 && pd != null) {
				Set<String> nl = pd.getStringValues().get(FileHandler.FILENAME);
				if (nl != null) {
					if (nl.size() > 0) {
						return nl.iterator().next();
					}
				}
				return "<none>";
			}
			if (arg1 == 1 && pd != null) {
				if (pd.getPost() != null) {
					if (pd.getPost().getPost() != null) {
						return pd.getPost().getPost().getFileReferenceDigest();
					}
				}
			}
			return null;
		}
		
	}
	
	private JPanel PostPanel;
	
	private File TempDir;
	private PostDecoded Reference;
	private JLabel ReferenceLabel;
	private File NewReferenceFile;
	private HashMap<String, JTextField> StringValues; 
	private HashMap<String, JTextField> StringCompleteValues;
	private HashMap<String, JTextField> NumberValues;
	private HashMap<String, HashMap<String,JCheckBox>> StringSelect;
	private HashMap<String, ReferencesTableModel> References;
	private JTextPane Comment;
	private SimpleGUI GUI;
	private File ChooserDir;
	
	public static String COMMENT = "COMMENT";
	
	public NewExpandedPostDialog(SimpleGUI gui, String template, String tmpdir) {
		GUI = gui;
		ChooserDir = new File(".");
		TempDir = new File(tmpdir);
		
		setTitle("New Post");

		setBounds(100, 100, 750, 550);

		getContentPane().setLayout(new BorderLayout()); //getContentPane(), BoxLayout.PAGE_AXIS));

		getContentPane().add(contentPanel);
		contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS)); // BoxLayout(contentPanel, BoxLayout.PAGE_AXIS));
		
		setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
		
		final JPanel buttonpanel = new JPanel();
		buttonpanel.setBorder(BorderFactory.createLineBorder(Color.black));
		buttonpanel.setMinimumSize(new Dimension(0, 150));
		JButton loadbtn = new JButton("Load Post Template");
		buttonpanel.add(loadbtn);
		loadbtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				JFileChooser chooser = new JFileChooser();
				chooser.setCurrentDirectory(ChooserDir);
				int returnVal = chooser.showOpenDialog(buttonpanel);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName());
					File f = chooser.getSelectedFile();
					try {
						setVisible(false);
						loadTemplateFile(PostPanel, f);
						setVisible(true);
					} catch (Exception e) {
						JOptionPane.showMessageDialog(buttonpanel, "There was a problem with that template file.");							
						e.printStackTrace();
					}
				}
				ChooserDir = chooser.getCurrentDirectory();
			}
		});
		ReferenceLabel = new JLabel("<none>");
		JButton attachfile = new JButton("Attach File");
		attachfile.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser = new JFileChooser();
				chooser.setCurrentDirectory(ChooserDir);
				int returnVal = chooser.showOpenDialog(buttonpanel);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName());
					File f = chooser.getSelectedFile();
					addFile(f);
				}	
				ChooserDir = chooser.getCurrentDirectory();
			}
		});
		
		buttonpanel.add(attachfile);
		JButton clearref = new JButton("Clear File");
		clearref.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				clearFile();
			}
		});
		buttonpanel.add(clearref);
		buttonpanel.add(ReferenceLabel);

		contentPanel.add(buttonpanel);

		PostPanel = new JPanel();
		PostPanel.setLayout(new MigLayout("", "", ""));
		PostPanel.setBorder(BorderFactory.createLineBorder(Color.black));
	
		JPanel buttonpanel2 = new JPanel();
		buttonpanel2.setBorder(BorderFactory.createLineBorder(Color.black));
		JButton clearall = new JButton("Clear All");
		clearall.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				clearValues();
			}
		});
		buttonpanel2.add(clearall);
		JButton post = new JButton("Post");
		buttonpanel2.add(post);
		post.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				doPost();
			}
		});
		JButton cancel = new JButton("Cancel");
		buttonpanel2.add(cancel);
		cancel.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				setVisible(false);
			}
		});
		
		File f = new File(template);
		if (f.exists()) {
			try {
				setVisible(false);
				loadTemplateFile(PostPanel, f);
				setVisible(true);
			}
			catch (Exception e) {
				JOptionPane.showMessageDialog(buttonpanel2, "There was a problem with that template file.");							
				e.printStackTrace();
			}
		}
		JScrollPane sp = new JScrollPane();
		sp.setViewportView(PostPanel);
		PostPanel.setMinimumSize(new Dimension(0, 500));
		contentPanel.add(sp);
		contentPanel.add(buttonpanel2);	
		setVisible(false);

	}
	
	public synchronized void doPost() {
		boolean oktopost = true;
		boolean hasdata = false;
		
		PostDecoded pd = new PostDecoded();
		
		if (StringSelect != null) {
			Iterator<Entry<String,HashMap<String,JCheckBox>>> i = StringSelect.entrySet().iterator();
			while (i.hasNext()) {
				Entry<String,HashMap<String,JCheckBox>> e = i.next();
				Iterator<Entry<String,JCheckBox>> i2 = e.getValue().entrySet().iterator();
				while (i2.hasNext()) {
					Entry<String,JCheckBox> e2 = i2.next();
					if (e2.getValue().isSelected()) {
						pd.pushStringValue(e.getKey(), e2.getKey());
						hasdata = true;
					}
				}
			}
		}
		if (StringValues != null) {
			Iterator<Entry<String,JTextField>> i = StringValues.entrySet().iterator();
			while (i.hasNext()) {
				Entry<String,JTextField> ent = i.next();
				String parts[] = ent.getValue().getText().split("\\s+");
				for (int cnt = 0; cnt < parts.length; cnt++) {
					pd.pushStringValue(ent.getKey(), parts[cnt]);
					hasdata = true;
				}
			}
		}
		if (StringCompleteValues != null) {
			Iterator<Entry<String,JTextField>> i = StringCompleteValues.entrySet().iterator();
			while (i.hasNext()) {
				Entry<String,JTextField> ent = i.next();
				String v = ent.getValue().getText();
				Matcher m = Pattern.compile("\\S+").matcher(v);
				if (m.find()) {
					pd.pushStringValue(ent.getKey(), v);
					hasdata = true;
				}
			}
		}
		if (NumberValues != null) {
			Iterator<Entry<String,JTextField>> i = NumberValues.entrySet().iterator();
			while (i.hasNext()) {
				Entry<String,JTextField> ent = i.next();
				String vs = ent.getValue().getText();
				if (vs.equals("")) {
					pd.getNumberValues().put(ent.getKey(), 0L);
				}
				else {
					try {
						long v = Long.valueOf(ent.getValue().getText());
						pd.getNumberValues().put(ent.getKey(), v);
						hasdata = true;
					}
					catch (Exception exp) {
						oktopost = false;
						JOptionPane.showMessageDialog(contentPanel, ent.getKey() + " should be a number.");							
					}
				}
			}
		}
		if (References != null) {
			Iterator<Entry<String,ReferencesTableModel>> i = References.entrySet().iterator();
			while (i.hasNext()) {
				Entry<String,ReferencesTableModel> ent = i.next();
				Iterator<PostDecoded> i2 = ent.getValue().List.iterator();
				while (i2.hasNext()) {
					PostDecoded npd = i2.next();
					Object ref = npd.getPost().getPost().getFileReferenceDigest();
					if (ref != null) {
						pd.pushReferenceValue(ent.getKey(), ref);
						hasdata = true;
					}
				}
			}
		}
		Post p = new Post();
		if (Reference != null) {
			p.setFileReferenceDigest(Reference.getPost().getPost().getFileReferenceDigest());
			hasdata = true;
		}
		if (Comment != null) {
			//pd.setComment(Comment.getText());
			//Put in a key-value so we can search it without adding
			//another stupid term to the search api.
			pd.pushStringValue(COMMENT, Comment.getText());
			hasdata = true;
		}
		
		if (oktopost && hasdata) {
			try {
				LocalPost lp = new LocalPost();
				lp.setPost(p);
				pd.setPost(lp);
				File tf = File.createTempFile("newpost", ".dat", TempDir);
				p.setMessage(tf);
				if (Reference != null) {
					Set<String> fnstr = Reference.getStringKeySet(FileHandler.FILENAME);
					if (fnstr != null) {
						pd.getStringValues().put(FileHandler.FILENAME, fnstr);
					}
					Long num = Reference.getNumberValues().get(FileHandler.LARGEFILEKEY);
					if (num != null) {
						pd.getNumberValues().put(FileHandler.LARGEFILEKEY, num);
					}
				}
				Codec.ecnode(pd);
				if (NewReferenceFile != null) {
					final File newfile = NewReferenceFile;
					final PostDecoded rpd = pd;
					final UploadDialog ud = new UploadDialog();
					ud.setVisible(true);
					EventQueue.invokeLater(new Runnable() {
						@Override
						public void run() {
							GUI.insertFile(newfile, rpd);
							ud.setVisible(false);
						}
					});
				}
				else {
					if (Reference != null) {
						GUI.addLocalPost(p.getMessage(), Reference.getPost().getPost().getFileReferenceDigest());
					}
					else {
						GUI.addLocalPost(p.getMessage(), null);						
					}
				}
				setVisible(false);
			}
			catch (Exception exc) {
				exc.printStackTrace();
			}
		}		
	}
	
	private void clearStringOptions() {
		Iterator<Entry<String,HashMap<String,JCheckBox>>> i1 = StringSelect.entrySet().iterator();
		while (i1.hasNext()) {
			Entry<String,HashMap<String,JCheckBox>> e1 = i1.next();
			Iterator<JCheckBox> i2 = e1.getValue().values().iterator();
			while (i2.hasNext()) {
				JCheckBox jcb = i2.next();
				jcb.setSelected(false);
			}
		}		
	}
	
	public synchronized void clearValues() {
		clearFile();
		clearStringOptions();
		if (StringValues != null) {
			Iterator<Entry<String,JTextField>> i = StringValues.entrySet().iterator();
			while (i.hasNext()) {
				i.next().getValue().setText("");
			}
		}
		if (StringCompleteValues != null) {
			Iterator<Entry<String,JTextField>> i = StringCompleteValues.entrySet().iterator();
			while (i.hasNext()) {
				i.next().getValue().setText("");
			}
		}
		if (NumberValues != null) {
			Iterator<Entry<String,JTextField>> i = NumberValues.entrySet().iterator();
			while (i.hasNext()) {
				i.next().getValue().setText("");
			}
		}
		if (References != null) {
			Iterator<Entry<String, ReferencesTableModel>> i = References.entrySet().iterator();
			while (i.hasNext()) {
				Entry<String,ReferencesTableModel> e = i.next();
				e.getValue().clear();
			}
		}
		if (Comment != null) {
			Comment.setText("");
		}
	}
	
	public synchronized void addFile(File f) {
		if (f != null && f.exists() && f.isFile()) {
			NewReferenceFile = f;
			Reference = null;
			ReferenceLabel.setText(NewReferenceFile.getName());
		}
	}
	
	public synchronized void clearFile() {
		NewReferenceFile = null;
		Reference = null;
		ReferenceLabel.setText("<none>");
	}
	
	public synchronized void addReference(String key, PostDecoded p) {
		ReferencesTableModel m = References.get(key);
		if (m != null) {
			m.addNew(p);
		}
	}
	
	public synchronized void addReference(PostDecoded pd) {
		Reference = pd;
		NewReferenceFile = null;
		Set<String> fn = pd.getStringKeySet(FileHandler.FILENAME);
		if (fn != null) {
			if (fn.size() > 0) {
				ReferenceLabel.setText(fn.iterator().next());
			}
		}
	}
	
	public synchronized Set<String> getReferenceKeys() {
		HashSet<String> hs = new HashSet<String>();
		Iterator<String> i = References.keySet().iterator();
		while (i.hasNext()) {
			hs.add(i.next());
		}
		return hs;
	}
	
	private void loadTemplateFile(JPanel panel, File templatefile) throws IOException {
		StringValues  = new HashMap<String, JTextField>           ();
		StringCompleteValues = new HashMap<String, JTextField>    ();
		NumberValues  = new HashMap<String, JTextField>           ();
		StringSelect  = new HashMap<String, HashMap<String,JCheckBox>>();
		References    = new HashMap<String, ReferencesTableModel> ();
		Comment       = new JTextPane();

		panel.removeAll();
		int rows = 0;
		FileReader fr = new FileReader(templatefile);
		BufferedReader br = new BufferedReader(fr);
		String cmd = br.readLine();
		while (cmd != null) {
			String lp[] = cmd.split("\\s+");
			if (lp[0].equals("STRO") && lp.length > 2) {
				if (StringSelect.get(lp[1]) == null) {
					JLabel l = new JLabel(lp[1]);
					panel.add(l, "cell 0 " + rows + ",alignx left");
					HashMap<String,JCheckBox> cblist = new HashMap<String,JCheckBox>();
					StringSelect.put(lp[1], cblist);
					for (int cnt = 2; cnt < lp.length; cnt++) {
						JCheckBox cb = new JCheckBox(lp[cnt]);
						cblist.put(lp[cnt], cb);
						panel.add(cb, "cell 1 " + rows + ",growx");
					}
					rows++;
				}
			}
			if (lp[0].equals("STR") && lp.length == 2) {
				if (StringValues.get(lp[1]) == null) {
					JLabel l = new JLabel(lp[1]);
					panel.add(l, "cell 0 " + rows + ",alignx left");
					JTextField tf = new JTextField();
					panel.add(tf, "cell 1 " + rows + ",growx");
					StringValues.put(lp[1], tf);
					rows++;
				}
			}
			if (lp[0].equals("STRC") && lp.length == 2) {
				if (StringCompleteValues.get(lp[1]) == null) {
					JLabel l = new JLabel(lp[1]);
					panel.add(l, "cell 0 " + rows + ",alignx left");
					JTextField tf = new JTextField();
					panel.add(tf, "cell 1 " + rows + ",growx");
					StringCompleteValues.put(lp[1], tf);
					rows++;
				}
			}
			if (lp[0].equals("NUM") && lp.length == 2) {
				if (NumberValues.get(lp[1]) == null) {
					JLabel l = new JLabel(lp[1]);
					panel.add(l, "cell 0 " + rows + ",alignx left");
					JTextField tf = new JTextField();
					panel.add(tf, "cell 1 " + rows + ",growx");
					NumberValues.put(lp[1], tf);
					rows++;
				}
			}
			if (lp[0].equals("REF") && lp.length == 2) {
				if (References.get(lp[1]) == null) {
					JLabel l = new JLabel("is a " + lp[1] + " of");
					panel.add(l, "cell 0 " + rows + ",alignx left");
					ReferencesTableModel mod = new ReferencesTableModel();
					JTable t = new JTable(mod);
					JScrollPane p = new JScrollPane(t);
					p.setMaximumSize(new Dimension(Integer.MAX_VALUE, 100));
					panel.add(p, "cell 1 " + rows + ",growx");
					JButton but = new JButton("Clear");
					panel.add(but, "cell 1 " + rows);
					but.setActionCommand(lp[1]);
					but.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent arg0) {
							clearReferences(arg0.getActionCommand());
						}
					});
					References.put(lp[1], mod);
					rows++;
				}
			}
			if (lp[0].equals("COMMENT")) {
				JLabel l = new JLabel("Comment");
				panel.add(l, "cell 0 " + rows + ",alignx left,grow");
				JScrollPane sp = new JScrollPane();
				sp.setMinimumSize(new Dimension(0, 200));
				sp.setViewportView(Comment);
				panel.add(sp, "cell 1 " + rows + ",growx");
				rows++;
			}
			cmd = br.readLine();
		}
		br.close();
	}

	private void clearReferences(String ref) {
		ReferencesTableModel m = References.get(ref);
		if (m != null) {
			m.clear();
		}
	}
	
}
