import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;

import javax.swing.border.EmptyBorder;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.border.TitledBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.border.LineBorder;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.URL;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.imageio.ImageIO;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.List;
import java.awt.*;

import java.awt.*;
import java.beans.DefaultPersistenceDelegate;
import java.beans.Encoder;
import java.beans.Statement;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;

// MVC   modelisation  visualization  command

public class jdialog02 extends JDialog 
{
	private static JTable table;
	private JTree tree;
///	private static DefaultTableModel xxxmodel;
	private boolean close_Jdialog = false;
	private TreeModel model;
	private List<TreeNode[]> expanded;
	private JButton btn_load_tree;
	private JButton btn_save_tree;
	private JButton btn_load_table;
	private JButton btn_save_table;
	
	private JButton btn_analyse;
	
	
	private File file = new File("TableModel.xml");	
	private DefaultTableModel tableModel; 
	private JFileChooser myJFileChooser = new JFileChooser(new File(".")); 
	
	private Class_plan intermediaire;   
	
	private ArrayList<String> tree_node = new ArrayList<String>();
	
	public jdialog02(JFrame f, boolean modal) 
	{
       super(f, modal);
       
              
       
       // fermer la fenetre
       addWindowListener(new java.awt.event.WindowAdapter() 
       {
           public void windowClosing(java.awt.event.WindowEvent e) 
           {
               serialize();
        	   dispose();
           }
       });
       
       expanded = new ArrayList<TreeNode[]>();
   
       init();
     
	}
  
	private void init()
	{
	  	setResizable( false );
		setBounds(100, 100, 926, 550);
		setTitle("Test definition - debug ...");
		getContentPane().setLayout(null);
     	
		ImageIcon icon = null;
		icon = createImageIcon("resources/settings.png", "");
		setIconImage( icon.getImage() );
		
		setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
		
		JScrollPane scrollPane_2 = new JScrollPane();
		scrollPane_2.setBounds(50, 39, 183, 194);
		getContentPane().add(scrollPane_2);
		
		
		DefaultMutableTreeNode root = new DefaultMutableTreeNode("Plan");
		
		
		
		tree = new JTree(root);
		//tree.setRowHeight(45);
		//tree = new JTree();
		
		tree.setComponentPopupMenu(new SelectionTreePopupMenu());
		
		scrollPane_2.setViewportView(tree);
		 
		tree.addMouseListener(new MouseAdapter() 
		{
		      public void mouseClicked(MouseEvent me) 
		      {
		    	  doMouseClicked(me);
		      }
	    });
		
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(294, 39, 532, 159);
		getContentPane().add(scrollPane);
		
		String[] columnNames =  {"Test", "Descrition" , "rien"};
	     
	    Object[][] data = {
							{null, null, null},
							{null, null, null},
							{null, null, null},
							{null, null, null},
							{null, null, null},
						  };
		
		tableModel = new DefaultTableModel(data, columnNames)
		{
	        @Override
	        public boolean isCellEditable(int row, int column)
	        {
	            // make read only fields except column 0,13,14
	            return column == 1 || column == 2 ;
	        }
	    };
		
		
		
	    table = new JTable(tableModel);
	    table.setRowHeight(30);
	    table.setFont(new Font("Serif", Font.BOLD, 20));

	    
	/*    
		JTable table = new JTable(); 
        Object[] columns = {"Id","First Name","Last Name","Age"};
        DefaultTableModel model = new DefaultTableModel();
        model.setColumnIdentifiers(columns);
        
        // set the model to the table
        table.setModel(model);
        
        table.setBackground(Color.LIGHT_GRAY);
        table.setForeground(Color.black);
        //Font font = new Font("",1,22);
        //table.setFont(font);
        //table.setRowHeight(30);
*/
	    
		scrollPane.setViewportView(table);

		/*******************/
		
		btn_load_tree  = new JButton("Load");
		btn_load_tree.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				System.out.println("Btn load  \n");
				deSerialize();
			}
		});
		btn_load_tree.setBounds(50, 257, 89, 23);
		getContentPane().add(btn_load_tree);
				
		btn_save_tree = new JButton("Save");
		btn_save_tree.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				System.out.println("Btn save  \n");
				serialize();
			}
		});
		btn_save_tree.setBounds(161, 257, 89, 23);
		getContentPane().add(btn_save_tree);
		
		/*******************/
		
		btn_load_table  = new JButton("Load");
		btn_load_table.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				System.out.println("Btn load table \n");
				loadTable(); 
			}
		});
		btn_load_table.setBounds(450, 257, 89, 23);
		getContentPane().add(btn_load_table);
				
		btn_save_table = new JButton("Save");
		btn_save_table.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				System.out.println("Btn save table  \n");
				saveTable(file); 
			}
		});
		btn_save_table.setBounds(550, 257, 89, 23);
		getContentPane().add(btn_save_table);
		
		/*******************/
		
		
		btn_analyse  = new JButton(" ++++ ");
		btn_analyse.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				System.out.println("Btn analyse  \n");
				
				
				tableModel.addRow(new Object[]{null,null,null});
/*				
				TreeModel model = tree.getModel();
				System.out.println(getTreeText(model, model.getRoot(), ""));
				
				System.out.println("******************************");
				printDescendants(root);
				 
				 traverse(tree);
				 
				 if(tree_node.size() != 0)
				 {
					 for(int i = 0; i < tree_node.size() ; i++)
					 {
						 //if(tree_node.get(i).indexOf("--") != -1)
						 //{
							 tableModel.setValueAt( tree_node.get(i) , i, 0);
						 //}
					 }	 
				 }
				 else
				 {
			    	  String msg = String.format("ERROR: Node not find !.");
			          JOptionPane.showMessageDialog(tree, msg, "Message", JOptionPane.ERROR_MESSAGE);

				 }
*/					 
				 split02.myArea.append(" [ INFO ]: blabla " + "\n");
				
				//getModel()
				// https://imss-www.upmf-grenoble.fr/prevert/Prog/Java/swing/JTree.html
				// https://www.rgagnon.com/javadetails/java-0313.html    traverse 
				
			}
		});
		btn_analyse.setBounds(250, 257, 89, 23);
		getContentPane().add(btn_analyse);
		
		/*******************/
		
		JSeparator separator = new JSeparator();
		separator.setBounds(240, 302, 440, 2);
		getContentPane().add(separator);
	
		/*******************/
		
		JButton btn_ok = new JButton("OK");
		btn_ok.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				close_Jdialog = false;
				System.out.println("Btn Cancel  \n");
				dispose();
			}
		});
		btn_ok.setBounds(135, 391, 89, 23);
		getContentPane().add(btn_ok);
	
		/*******************/
		
		JButton btn_cancel = new JButton("Cancel");
		btn_cancel.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e) 
			{
				close_Jdialog = false;
				System.out.println("Btn Cancel  \n");
				dispose();
			}
		});
		btn_cancel.setBounds(359, 391, 89, 23);
		getContentPane().add(btn_cancel);
		
		/*******************/
	}
	
	
	private  String getTreeText(TreeModel model, Object object, String indent) 
	{
	    String myRow = indent + object + "\n";
	    for (int i = 0; i < model.getChildCount(object); i++) {
	        myRow += getTreeText(model, model.getChild(object, i), indent + "  ");
	    }
	    return myRow;
	}
	
	private void saveStatus() 
	{
        //save the expanded Nodes:
        expanded = new ArrayList<TreeNode[]>();
        collectStatusInfo(model.getRoot());
	}

	private void restoreStatus() 
	{
        //expand the saved Nodes:
        for (int i = expanded.size() - 1; i > -1; i--) 
        {
        	TreeNode[] ar = expanded.get(i);
	        tree.expandPath(new TreePath(ar));
        }
	}

	private void collectStatusInfo(final Object o) 
	{
		int cc = model.getChildCount(o);
	    for (int i = 0; i < cc; i++) 
	    {
	    	DefaultMutableTreeNode child = (DefaultMutableTreeNode) model.getChild(o, i);
	        TreeNode[] ar = child.getPath();
	        if (!model.isLeaf(child) && tree.isExpanded(new TreePath(ar))) 
	        {
	        	expanded.add(ar);
	            collectStatusInfo(child);
	        }
        }
	}
	
	// https://wiki.byte-welt.net/wiki/JTree_Zustand_speichern
	public void serialize() 
	{
		try 
		{
			XMLEncoder o = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("tree.xml")));
	        o.writeObject(tree.getModel());
	        o.writeObject(expanded);
	        o.close();
        } 
		catch (IOException e) 
		{
			e.printStackTrace();
        }
	}

	@SuppressWarnings("unchecked")
	private void deSerialize() 
	{
        try 
        {
        	XMLDecoder d = new XMLDecoder(new BufferedInputStream(new FileInputStream("tree.xml")));
	        tree.setModel((TreeModel) d.readObject());
	        expanded = (List<TreeNode[]>) d.readObject();
	        d.close();
        } 
        catch (FileNotFoundException ex) 
        {
	    }
	}
    
	public ImageIcon createImageIcon(String path,  String description) 
	{
		URL imgURL = getClass().getResource(path);

		if (imgURL != null)
		{
  			return new ImageIcon(imgURL, description);
		} 
		else 
		{
			System.err.println("Couldn't find file: " + path);
			return null;
		}
	}
	
	/******************************************/
	
	private void saveTable() 
	{
        if (myJFileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION ) 
        {
            saveTable(myJFileChooser.getSelectedFile());
        }
    }
     
    private void saveTable(File file) 
    {
        try 
        {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
            out.writeObject(tableModel.getDataVector());
            out.writeObject(getColumnNames());
            out.close();
        }
        catch (Exception ex) 
        {
            ex.printStackTrace();
        }
    }
    
    private Vector<String> getColumnNames() 
    {
        Vector<String> columnNames = new Vector<String>();
        for (int i = 0; i < table.getColumnCount(); i++)
            columnNames.add(table.getColumnName(i) );
        return columnNames;
    }
    
    private void loadTable() 
	{
    	if (myJFileChooser.showOpenDialog(this) ==  JFileChooser.APPROVE_OPTION )
	            loadTable(myJFileChooser.getSelectedFile());
    }
	 
    private void loadTable(File file) 
	{
        try 
        {
        	ObjectInputStream in = new ObjectInputStream( new FileInputStream(file));
	        Vector rowData = (Vector)in.readObject();
	        Vector columnNames = (Vector)in.readObject();
	        tableModel.setDataVector(rowData, columnNames);
	        in.close();
        }
        catch (Exception ex) 
        {
	        ex.printStackTrace();
	    }
    }
	
	/******************************************/
	
    public  void printDescendants(TreeNode root) 
    {
        System.out.println(root);
        Enumeration children = root.children();
        if (children != null) 
        {
          while (children.hasMoreElements()) 
          {
            printDescendants((TreeNode) children.nextElement());
          }
        }
    }
    
    public void traverse(JTree tree) 
    { 
        TreeModel model = tree.getModel();
        if (model != null) 
        {
            Object root = model.getRoot();
            System.out.println(root.toString());
            node_hierarchie(model,root);    
        }
        else
        {	
           System.out.println("Tree is empty.");
        }   
    }
        
    public void node_hierarchie(TreeModel model, Object o)
    {
    	
    	tree_node.clear();
    	
        int  cc;
        cc = model.getChildCount(o);
        for( int i=0; i < cc; i++) 
        {
        	Object child = model.getChild(o, i );
        	if (model.isLeaf(child))
        	{	
        		System.out.println(child.toString());
        		tree_node.add(child.toString());
        	}
        	else 
        	{
        		System.out.print(child.toString()+"--");
        		tree_node.add(child.toString()+"--");
        		node_hierarchie(model,child); 
        	}	
           

            
        }
    } 
    
	public void doMouseClicked(MouseEvent me) 
	{
		TreePath tp = tree.getPathForLocation(me.getX(), me.getY());
		 //   if (tp != null)
		 //     jtf.setText(tp.toString());
		 //   else
		 //     jtf.setText("");
		System.out.println(tp);   
		
		 Object[] row = new Object[3];
		 row[0] = "a";
         row[1] = "b";
         row[2] = "c";
         
         //tableModel.setValueAt("VALUE", 0, 0);
	}
  
}

class SelectionTreePopupMenu extends JPopupMenu 
{
	  protected TreePath path;

	  int NODE_MAXIMUM_LEVELS = 2;
	  
	  private Class_plan intermediaire = new Class_plan();

	  
	  protected SelectionTreePopupMenu() 
	  {
	    super();

	     // intermediaire.addSequence(new TestPlan());
	    
	    add("add child node").addActionListener(e -> 
	    {
	      JTree tree = (JTree) getInvoker();
	      TreePath path = tree.getSelectionPath();
	      if (path.getPathCount() <= NODE_MAXIMUM_LEVELS) 
	      {
		      DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
		      DefaultMutableTreeNode self = (DefaultMutableTreeNode) path.getLastPathComponent();
		      DefaultMutableTreeNode child = new DefaultMutableTreeNode("New child node");
		      self.add(child);
		      model.reload(self);
		  
		      intermediaire.addSequence(new TestPlan() );
		      
    	//	graph_line.addLines( new LineObj((int)StartPoint.getX(), (int)StartPoint.getY(), (int)EndPoint.getX(), (int)EndPoint.getY() , Color.BLUE ) );

		      
	      // or: model.insertNodeInto(child, self, self.getChildCount());
	      }
	      else 
	      {
	    	  String message = String.format("ERROR: Maximum levels of %d exceeded.", NODE_MAXIMUM_LEVELS);
	          JOptionPane.showMessageDialog(tree, message, "add node", JOptionPane.ERROR_MESSAGE);
	      }
		      
	    });
	    
	    addSeparator();
	    
	    add("insert preceding sibling node").addActionListener(e -> 
	    {
	      JTree tree = (JTree) getInvoker();
	      DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
	      DefaultMutableTreeNode self = (DefaultMutableTreeNode) path.getLastPathComponent();
	      DefaultMutableTreeNode parent = (DefaultMutableTreeNode) self.getParent();
	      DefaultMutableTreeNode child = new DefaultMutableTreeNode("New preceding sibling");
	      int index = model.getIndexOfChild(parent, self);
	      parent.insert(child, index);
	      model.reload(parent);
	      // or: model.insertNodeInto(child, parent, index);
	    });
	    
	    add("insert following sibling node").addActionListener(e -> 
	    {
	      JTree tree = (JTree) getInvoker();
	      DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
	      DefaultMutableTreeNode self = (DefaultMutableTreeNode) path.getLastPathComponent();
	      DefaultMutableTreeNode parent = (DefaultMutableTreeNode) self.getParent();
	      DefaultMutableTreeNode child = new DefaultMutableTreeNode("New following sibling");
	      int index = model.getIndexOfChild(parent, self);
	      parent.insert(child, index + 1);
	      model.reload(parent);
	      // or: model.insertNodeInto(child, parent, index + 1);
	    });
	    
	    
	    add("Remove").addActionListener(e -> 
	    {
	    	  DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
		      if (!node.isRoot()) 
		      {
		        JTree tree = (JTree) getInvoker();
		        DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
		        model.removeNodeFromParent(node);
		      }
	    });
		    
	    add("Edit").addActionListener(e -> 
	    {
	    	JTextField textField = new JTextField(); //24
	    	Object node = path.getLastPathComponent();
		      
	    	DefaultMutableTreeNode leaf = (DefaultMutableTreeNode) node;
	    	textField.setText(leaf.getUserObject().toString());
	    	JTree tree = (JTree) getInvoker();
	        
	    	if( !textField.getText().equals("Plan"))
	    	{	
		    	int ret = JOptionPane.showConfirmDialog(tree, textField, "edit", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
		    	if (ret == JOptionPane.OK_OPTION) 
		    	{
		    		Optional.ofNullable(textField.getText())
		            .filter(str -> !str.trim().isEmpty())
		            .ifPresent(str -> {
		              DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
		              model.valueForPathChanged(path, str);
		            });
		    	}
	    	}
	    	 else 
		     {
		    	  String message = String.format("ERROR: Plan level cannot be changed !.", NODE_MAXIMUM_LEVELS);
		          JOptionPane.showMessageDialog(tree, message, "Edit node", JOptionPane.ERROR_MESSAGE);
		      }
	    });
	    
	  }

	  @Override 
	  public void show(Component c, int x, int y) 
	  {
	    if (c instanceof JTree) 
	    {
	    	JTree tree = (JTree) c;
	    	path = tree.getPathForLocation(x, y);
	    	Optional.ofNullable(path).ifPresent(tp -> super.show(c, x, y));
	    }
	  }

}


//// Traversing Trees

// Set the selected Jtree Node to JTable


/*
public void printDescendants(TreeNode root) {
	  System.out.println(root);
	  Enumeration children = root.children();
	  if (children != null) {
	    while(children.hasMoreElements()) {
	      printDescendants((TreeNode)children.nextElement());
	    }
	  }
	}*/


/*
start at root
If is a leaf - Print node name and return
Print --- node name ----
If node has children - recurse with each child (starting at 2)
Print +++ Node name ++++


public static void print(DefaultMutableTreeNode aNode)
{
    String name = aNode.toString();
    int level= aNode.getLevel();
    String placement = "";
    while (level > 0)
    {
        placement += ">";
        level--;
    }
    if(aNode.isLeaf())
    {
        System.out.println(placement + name);
        return;
    }

    System.out.println(placement + "--- " + name + " ---");
    for(int i = 0 ; i < aNode.getChildCount() ; i++)
    {
        print((DefaultMutableTreeNode)aNode.getChildAt(i));
    }
    System.out.println(placement + "+++ " + name + " +++");
}
*/