package com.objex.anywherewrapper;


import com.objex.panywhere.IndividualAddEvent;
import com.objex.panywhere.IndividualAddListener;
import com.objex.panywhere.Data;
import com.objex.panywhere.DataType;
import com.objex.panywhere.DatabaseField;
import com.objex.panywhere.DatabaseTable;
import com.objex.panywhere.IndividualDeleteEvent;
import com.objex.panywhere.IndividualDeleteListener;
import com.objex.panywhere.IconClickEvent;
import com.objex.panywhere.IconClickListener;
import com.objex.panywhere.ImportEvent;
import com.objex.panywhere.ImportListener;
import com.objex.panywhere.Individual;
import com.objex.panywhere.Legend;
import com.objex.panywhere.LegendItem;
import com.objex.panywhere.ProgenyAnywhere;
import com.objex.panywhere.ProgressMonitorDialog;
import com.objex.panywhere.SmartDrawService;
import com.objex.panywhere.Subtext;
import com.objex.panywhere.SubtextLegend;
import com.objex.panywhere.SubtextLegendItem;
import com.objex.panywhere.data.TableData;
import com.objex.panywhere.events.DragEvent;
import com.objex.panywhere.events.DrawingListener;
import com.objex.panywhere.events.GenderChangeEvent;
import com.objex.panywhere.events.IndividualListener;
import com.objex.panywhere.events.IndividualPropertyChangeEvent;
import com.objex.panywhere.events.IndividualsDeleteEvent;
import com.objex.panywhere.events.IndividualsDropEvent;
import com.objex.panywhere.events.PedigreeListener;
import com.objex.panywhere.events.PedigreePropertyChangeEvent;
import com.objex.panywhere.events.RelationshipChangeEvent;
import com.objex.panywhere.events.RelationshipConnectionEvent;
import com.objex.panywhere.events.RelationshipDeleteEvent;
import com.objex.panywhere.events.RelationshipListener;
import com.objex.panywhere.events.SpouseRelationshipChangeListener;
import com.objex.panywhere.events.TwinRelationshipChangeEvent;
import com.objex.panywhere.events.TwinRelationshipChangeListener;
import com.objex.panywhere.subtext.TableSubtextLegendItem;
import com.objex.progeny.anywhere.data.ChromosomeLegendItem;
import com.objex.progeny.anywhere.data.DataTRF;
import com.objex.progeny.anywhere.data.MarkerData;
import com.objex.progeny.anywhere.data.MarkerLegend;
import com.objex.progeny.anywhere.data.MarkerLegendItem;
import com.objex.progeny.anywhere.data.XRFCustomData;
import com.objex.progeny.anywhere.data.XRFFolder;
import com.objex.progeny.anywhere.enums.RELATIONSHIP;
import com.objex.progeny.anywhere.fields.XRFField;
import com.objex.progeny.anywhere.fields.data.XRFData;
import com.objex.progeny.anywhere.fields.data.XRFTableData;
import com.objex.progeny.anywhere.legend.subtext.XRFSubtextLegendItem;
import com.objex.progeny.anywhere.legend.symbols.XRFSymbolsLegendItem;
import com.sun.corba.se.spi.orbutil.threadpool.ThreadPool;
import java.applet.Applet;
import java.applet.AppletContext;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.MenuElement;
import javax.swing.ProgressMonitorInputStream;
import javax.swing.SpringLayout;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import samp.AddSampleDlg;



/**
 *
 * @author  Melody Pedzisai - Objex Inc
 *
 */
public class ProgenyAnywhereWrapper extends JApplet implements Runnable, IndividualListener, RelationshipListener, PedigreeListener, SpouseRelationshipChangeListener, TwinRelationshipChangeListener {



     /**
     * Relationship string for mother 
     */
    public static final int MOTHER   = 1;
    
    /**
     * Relationship string for father 
     */
    public static final int FATHER   = 2;
    
    /**
     * Relationship string for sister 
     */
    public static final int SISTER   = 3;
    
    /**
     * Relationship string for brother 
     */
    public static final int BROTHER  = 4;
    
    /**
     * Relationship string for daughter
     */
    public static final int DAUGHTER = 5;
    
    /**
     * Relationship string for SON
     */
    public static final int SON      = 6;    
    
    /**
     * Relationship string for Twin Sister
     */
    public static final int TWINSISTER   = 7;
    
    /**
     * Relationship string for Twin Brother 
     */
    public static final int TWINBROTHER   = 8;
    
    
    /**
     * Relationship string for spouse 
     */
    public static final int SPOUSE   = 9;

    private static final String STANDARD_MESS_CANNOT_SAVE = "From this point on all changes to pedigree will not be saved to database";
    private static final String STANDARD_MESSAGE_PED_WILLNOTSAVE = "Any changes you make to this pedigree will not be saved";
    private static final String STANDARD_MESSAGE_DUE_TO = "due to server error";
    
    
    
    private static final String SPACE = "";
    public static final int CONSANG_MASK =1;
    public static final int SEPARATED_MASK =2;
    public static final int DIVORCED_MASK =4;
    public static final int CASUAL_MASK =8;
    public static final int NOISSUE_MASK =16;
    public static final int INFERTILE_MASK =32;
    
    private ProgenyAnywhere m_anywhere;
    static JFrame frame = new JFrame("Progeny Anywhere ");
    Thread runner = null;
    boolean appletcontext = false;
    JScrollPane jsp = null;
    Applet app = null;
    int ii_maxfieldid = 0;        
    Individual m_currentIndividual;
    WindowListener m_WindowListener;            
    boolean ib_subtext_editor_visible = false;
    private int ii_familyid;
    private int ii_user_token;
    private int ii_pedigree_security_token;
    private String is_application_context = null;//"FIAT";
    private String is_familyname = "";
    private int ii_folderid = -1;
    private Individual m_current_right_clicked_individual;
    Map<Integer, Integer> m_upn_crossref = new Hashtable(); //key s local UPN and value is Progeny(Server) UPN)
    boolean ib_importing = false, ib_locked = false;
    ThreadPool p;    
    private boolean  ib_getting_save_events = false, ib_stale_pedigree = false, ib_moved = false, ib_smartdraw = false;
    private boolean ib_stop  = false, ib_events_thread_running = false, ib_error = false;
    private Boolean ib_changed = Boolean.FALSE;    
    private  ExecutorService m_threadExecutor = Executors.newFixedThreadPool( 3 );    
    private URL m_getEventsURL;
    private HttpURLConnection m_getEventsConn;
    private boolean ib_running_as_applet = false;
    boolean ib_inited = false;
    private boolean ib_started = false, ib_smartdrawon_import = false;
    private AppletContext context = null;
    private boolean ib_xml_read_pending = false;
    private ProgressMonitorDialog m_xmlread_progress_bar = null;
    private String m_JSESSIONID;
    private Map<String, Boolean> progeny_properties = new HashMap();
    private int ib_focus_after_close_count = 0;


    static {
        System.setProperty("com.objex.xml.parser", "validating"); //values are "validating and non-validating        
    }


    private Runnable readXMLRunnable = new Runnable() {
        public void run() {
            int count = 1;
            m_xmlread_progress_bar = new ProgressMonitorDialog(m_anywhere.m_canvas, "Loading pedigree data from server", "Reading", 0, count * 10000, true);
            while (ib_xml_read_pending) {
                try {Thread.sleep(count * 10000 - 20);} catch (InterruptedException ie) {}
                if (ib_xml_read_pending) {
                   m_xmlread_progress_bar.setMax((count+1) * 10000);
                   m_xmlread_progress_bar.setProgress(count * 10000);
                }
                count += 1;
            }
        }
    };


    private abstract class RhinoCommunicationTask implements Runnable {

        private String threadName; // name of thread

        public RhinoCommunicationTask(String name) {
            threadName = name;
        }
    }

    

    



    IconClickListener m_IconClickListener = new IconClickListener() {
        public void iconClicked(IconClickEvent evt) {
            int li_cnt = evt.getClickCount();
            if (li_cnt == 2){//double click on Icon
                if (ib_stale_pedigree) {
                   JOptionPane.showMessageDialog(ProgenyAnywhereWrapper.this, new String[]{"The pedigree is in an incosistent state", "You cannot open the Individual Datasheet"}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
                }
                Individual l_ind = evt.getOwner();
                if (l_ind != null) {
                    boolean lb_changed = false;
                    synchronized(ib_changed) {
                        lb_changed = ib_changed;
                    }
                    if (lb_changed) {
                        int li_confirm = JOptionPane.showConfirmDialog(ProgenyAnywhereWrapper.this, new String[]{"The pedigree has been modified", "Do you wish to save and then continue to open IDS?"});
                        switch (li_confirm) {
                            case JOptionPane.YES_OPTION:
                                try {
                                    if (savePedigreeXMLString(false)) {
                                        fireIndividualDoubleClicked(l_ind);
                                    }
                                } catch (Exception e) {
                                }
                                break;
                            default:
                                break;
                        }
                    } else {
                         fireIndividualDoubleClicked(l_ind);
                    }
                }
            } else {                
                if (SwingUtilities.isRightMouseButton(evt)) {
                    m_current_right_clicked_individual = evt.getOwner();
                }
            }
        }
    };

    




    public ProgenyAnywhereWrapper() {      

    }




    public static void main(String[] args) throws HeadlessException {
        ProgenyAnywhereWrapper applet =  new ProgenyAnywhereWrapper();
        applet.ib_running_as_applet = false;
        try  {
            applet.init();
            applet.start();
            applet.addTooBarToApplication();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().setLayout(new BorderLayout());
            frame.getContentPane().add(applet, BorderLayout.CENTER);
            frame.setSize(Toolkit.getDefaultToolkit().getScreenSize().width  - 25,
                          Toolkit.getDefaultToolkit().getScreenSize().height - 50);
            frame.setVisible(true);
            frame.addWindowListener(new WindowAdapter() {
                public void windowClosed(WindowEvent we) {
                      System.exit(0);
                }
                public void windowClosing(WindowEvent we) {
                    System.exit(0);
                }
            });
        } catch (Exception ex) {
            ex.printStackTrace();
            System.exit(0);
        }
    }



    protected void staticParams() throws NumberFormatException {
        ii_familyid = 5668;
        this.ii_user_token = 20886204;
        this.ii_pedigree_security_token = -1;
        is_application_context = "Spider";
        is_familyname = "15";
        this.ii_folderid = 2;
    }
            



    protected HttpURLConnection getServletURLHttpGETStatic(String as_action, String ... as_params) throws Exception {
            String protocol = "http";
            String host = "localhost";
            int port = 8085;
            String servlet = "/Spider/progenyrpcservice.html";
            servlet += "?WHO=Applet";
            servlet += "&FAMILY_ID=" + ii_familyid;
            servlet += "&PARAM_FOLDERID="+ ii_folderid;
            servlet += ("&ACTION=" + as_action);
            servlet += "&UID=" + ii_user_token;

            for (String ls_param : as_params) {
                servlet += ls_param;
            }

            URL servletURL = new URL(protocol, host, port, servlet);
            HttpURLConnection conn = (HttpURLConnection)servletURL.openConnection();//conn.
            conn.setRequestMethod("GET");
            conn.setUseCaches(false);
            conn.setDoInput(true);
            conn.setConnectTimeout(180 * 1000);
            return conn;
    }


    protected HttpURLConnection getServletURLHttpPOSTStatic() throws Exception {
            String protocol = "http";
            String host = "localhost";
            int port = 8085;
            String servlet = "/Spider/progenyrpcservice.html";
            servlet += "?WHO=Applet";
            servlet += "&FAMILY_ID=" + ii_familyid;
            servlet += "&PARAM_FOLDERID="+ ii_folderid;
            servlet += "&UID=" + ii_user_token;
            URL servletURL = new URL(protocol, host, port, servlet);
            HttpURLConnection conn = (HttpURLConnection)servletURL.openConnection();
            conn.setRequestMethod("POST");
            conn.setUseCaches(false);
            conn.setDoOutput(true); //need this in order to be able to write to the output stream
            conn.setDoInput(true);
            conn.setConnectTimeout(180 * 1000);
            return conn;
    }

   

    protected void closeInOutStreams(ObjectInputStream ois, ObjectOutputStream oos, HttpURLConnection conn) {
        try {
            if (ois != null) {
                ois.close();
            }
            if (oos != null) {
                oos.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        } catch (Throwable t) {
        }
    }
    
    
    /**
     * Intialize the applet
     */
    public void init() {
        appletcontext = false;
        jsp = null;       
        ib_inited = true;
        getContentPane().setBackground(Color.red);
        int w = 600, h = 400;
        boolean lb_show_toolbar = false;

        try {            
            context = getAppletContext();
        } catch (Exception npe) {
        }        
        if (context != null) {
            appletcontext = true;
            String sw = getParameter("WIDTH"),
                    sh = getParameter("HEIGHT");            
            try {
                w = Integer.parseInt(sw);
                h = Integer.parseInt(sh);
                String ls_family = getParameter("FAMILY_ID");
                String ls_uid = getParameter("UID");                
                ii_familyid = Integer.parseInt(ls_family);
                this.ii_user_token = Integer.parseInt(ls_uid);
                this.ii_pedigree_security_token = Integer.parseInt(getParameter("PEDSEC"));
                
                is_application_context = getParameter("APPLICATION_CONTEXT");

                m_JSESSIONID = getParameter("JSESSIONID");
                
                is_familyname = getParameter("FAMILY_NAME");
                
                this.ii_folderid = Integer.parseInt(getParameter("FOLDER_ID"));
                lb_show_toolbar = Integer.parseInt(getParameter("SHOW_TOOLBAR")) == 1;
                
            } catch (NumberFormatException npe) {
                npe.printStackTrace();
            }
        } else {
                staticParams();
        }
        setSize(w, h);        
        
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            m_anywhere = new ProgenyAnywhere();
            m_anywhere.addRelationshipListener(this);
            m_anywhere.addIndividualListener(this);
            m_anywhere.addPedigreeListener(this);
            m_anywhere.addSpouseRelationshipChangeListener(this);
            m_anywhere.addTwinRelationshipChangeListener(this);            
            m_anywhere.setIconsubtextfont(new Font(m_anywhere.getIconsubtextfont().getName(), Font.PLAIN, 11));
            m_anywhere.setMatchspouses(true);
            m_anywhere.setIconheight(26);
            m_anywhere.setIconwidth(26);
            m_anywhere.setMarkerDisplayWidth(9);
            m_anywhere.setMarkerDisplayHeight(14);
            m_anywhere.setGenerationoffset(75);
            m_anywhere.setSubtextyvalue(m_anywhere.getIconheight() + 5 + m_anywhere.getIconsubtextfont().getSize2D() + 5);
            m_anywhere.setUseStandardProbandArrow(false);
            m_anywhere.setShowblueid(true);
            m_anywhere.addIconClickListener(m_IconClickListener);
                                    
            //Now add the m_anywhere as view of the JSP viewport
            jsp = new JScrollPane(m_anywhere.m_canvas, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
            
            m_anywhere.addIndividualAddListener(new IndividualAddListener() {
                public void individualAdded(final IndividualAddEvent event) {
                    if (ib_importing) {
                        return;
                    }
                    
                    synchronized (ib_changed) {
                        ib_changed = true;
                    }
                    Runnable task = new RhinoCommunicationTask("add relation task") {
                        public void run() {
                           addRelation(event.getAddedIndividual(), event.getToIndividual());
                        }
                    };
                    //TODO if connected to a server then enable line m_threadExecutor.execute(task);
                }
            });
              
            m_anywhere.addIndividualDeleteListener(new IndividualDeleteListener() {
                public void individualDeleted(IndividualDeleteEvent event) {
                    if (ib_importing) {
                        return;
                    }                    
                    synchronized (ib_changed) {
                        ib_changed = true;
                    }
                }
            });

            reassignPopupMenuElems();

            m_anywhere.addImportListener(m_import_Listener);
             
            getContentPane().add(jsp, BorderLayout.CENTER);
            if (lb_show_toolbar) {
                addTooBarToApplication();
            }            
            storeProgenyProperties();

        } catch (Exception e) {
            e.printStackTrace();
            m_anywhere = null;
        }               
    }//end init




    
    void storeProgenyProperties() {
               progeny_properties.put("showgrid", m_anywhere.isShowgrid());
               progeny_properties.put("snapgrid", m_anywhere.isSnaptogrid());
               progeny_properties.put("showpagebreaks", m_anywhere.isShowpagebreaks());
               progeny_properties.put("showfooter", m_anywhere.isShowfooter());
               progeny_properties.put("showheader", m_anywhere.isShowheader());
               progeny_properties.put("autodraw", m_anywhere.isAutodraw());
               progeny_properties.put("livedragging", m_anywhere.isLivedragging());
               progeny_properties.put("showlegend", m_anywhere.isShowlegend());
               progeny_properties.put("oneclickadd", m_anywhere.isOneclickadd());
               progeny_properties.put("showsubtextlegend", m_anywhere.isShowSubtextLegend());
               //progeny_properties.put("standardprobandarrow", m_anywhere.isUseStandardProbandArrow());
               //progeny_properties.put("probandarrowpos", m_anywhere.getProbandArrowPos());
               progeny_properties.put("showhaplotypes", m_anywhere.isShowhaplotypes());               

    }

    void addTooBarToApplication() {
        //Now add the menu and the tool bar to the Applet
        JToolBar jt = m_anywhere.getToolBar();
        jt.setVisible(true);
        getContentPane().add(jt, BorderLayout.NORTH);
        JToolBar tb = jt;
        Component buttons[] = tb.getComponents();
        for (int i = 0; i < tb.getComponentCount(); i++) {
            Component button = buttons[i];
            if (button != null && button instanceof JButton) {
                JButton bt = (JButton) button;
                bt.setVisible(false);
            }
        }
        jt.add(new JButton(new SaveAction()));
        jt.add(new JButton(new SSAction()));
        jt.add(new JButton(new PaletteAction()));
        jt.add(new JButton(new PropertiesAction()));
        jt.add(new JButton(new SmartDrawAction()));
    }


    private class SmartDrawAction  extends AbstractAction {

         public SmartDrawAction(String txt) {
             super(txt);
             putValue(Action.SHORT_DESCRIPTION, "SmartDraw");
         }

         public SmartDrawAction() {
             try {
                 ImageIcon icon = null;
                 URL url = ProgenyAnywhereWrapper.class.getResource("smartdraw.gif");
                 putValue(Action.NAME, "SmartDraw");
                 if (url  != null) {
                     icon = new ImageIcon(url);
                     putValue(Action.SMALL_ICON, icon);
                     //putValue(Action.NAME, "GGGGG");
                 } else {
                     putValue(Action.NAME, "SmartDraw");
                 }
             } catch (Exception e) {
                 putValue(Action.NAME, "SmartDraw");
             }
             putValue(Action.SHORT_DESCRIPTION, "SmartDraw");
         }

         public void actionPerformed(ActionEvent e) {
             m_anywhere.smartDraw();
         }
     }

    private class SaveAction  extends AbstractAction {

         public SaveAction(String txt) {
             super(txt);
             putValue(Action.SHORT_DESCRIPTION, "Save");
         }

         public SaveAction() {
             try {
                 ImageIcon icon = null;
                 URL url = ProgenyAnywhereWrapper.class.getResource("save.gif");
                 putValue(Action.NAME, "Save");
                 if (url  != null) {
                     icon = new ImageIcon(url);
                     putValue(Action.SMALL_ICON, icon);                     
                 } else {
                     putValue(Action.NAME, "Save Pedigree");
                 }
             } catch (Exception e) {
                 putValue(Action.NAME, "Save Pedigree");
             }
             putValue(Action.SHORT_DESCRIPTION, "Save Pedigree");
         }

         public void actionPerformed(ActionEvent e) {
             doOnSave();
         }
     }


    private class SSAction  extends AbstractAction {

         public SSAction(String txt) {
             super(txt);
             putValue(Action.SHORT_DESCRIPTION, "Spreadsheet");
         }

         public SSAction() {
             try {
                 ImageIcon icon = null;
                 URL url = ProgenyAnywhereWrapper.class.getResource("ss.gif");
                 putValue(Action.NAME, "Spreadsheet");
                 if (url  != null) {
                     icon = new ImageIcon(url);
                     putValue(Action.SMALL_ICON, icon);                     
                 } else {
                     putValue(Action.NAME, "Open Individual Spreadsheet");
                 }
             } catch (Exception e) {
                 putValue(Action.NAME, "Open Individual Spreadsheet");
             }
             putValue(Action.SHORT_DESCRIPTION, "Open Individual Spreadsheet");
         }

         public void actionPerformed(ActionEvent e) {
             doOnSS();
         }
     }



    private class PaletteAction  extends AbstractAction {

         public PaletteAction(String txt) {
             super(txt);
             putValue(Action.SHORT_DESCRIPTION, "Palette");
         }

         public PaletteAction() {
             try {
                 ImageIcon icon = null;
                 URL url = ProgenyAnywhereWrapper.class.getResource("palette.gif");
                 putValue(Action.NAME, "Palette");
                 if (url  != null) {
                     icon = new ImageIcon(url);
                     putValue(Action.SMALL_ICON, icon);
                     //putValue(Action.NAME, "GGGGG");
                 } else {
                     putValue(Action.NAME, "Show Individual Palette");
                 }
             } catch (Exception e) {
                 putValue(Action.NAME, "Show Individual Palette");
             }
             putValue(Action.SHORT_DESCRIPTION, "Show Individual Palette");
         }

         public void actionPerformed(ActionEvent e) {
              m_anywhere.showPaletteDialog(true);
         }
     }



    private class PropertiesAction  extends AbstractAction {

         public PropertiesAction(String txt) {
             super(txt);
             putValue(Action.SHORT_DESCRIPTION, "Properties");
         }

         public PropertiesAction() {
             try {
                 ImageIcon icon = null;
                 URL url = ProgenyAnywhereWrapper.class.getResource("properties.gif");
                 putValue(Action.NAME, "Properties");
                 if (url  != null) {
                     icon = new ImageIcon(url);
                     putValue(Action.SMALL_ICON, icon);
                     //putValue(Action.NAME, "GGGGG");
                 } else {
                     putValue(Action.NAME, "Show Properties");
                 }
             } catch (Exception e) {
                 putValue(Action.NAME, "Show Properties");
             }
             putValue(Action.SHORT_DESCRIPTION, "Show Properties");
         }

         public void actionPerformed(ActionEvent e) {
              m_anywhere.showPropertiesDialog(true);
         }
     }
    
    
    
    
    public static int getSpouseRelationshipStatus(Individual a_person, Individual a_spouse) {
        int li_status = 0;
        Individual p = a_person, spouse = a_spouse;
        if (!p.isMarried(spouse)) {                  
                  if (p.isDivorced(spouse)) {
                      li_status |= DIVORCED_MASK;
                  }
                  if (p.isSeparated(spouse)) {
                      li_status |= SEPARATED_MASK;
                  }
                   if (p.isCasual(spouse)) {
                       li_status |= CASUAL_MASK;
                   }
              if (p.isConsanguineous(spouse)) {
                 li_status |= CONSANG_MASK;
              }
              if (p.isInfertile(spouse)) {
                 li_status |= INFERTILE_MASK;
              }
               
              if (p.isNoissue(spouse)) {
                  li_status |= NOISSUE_MASK;
              }
        }          
        return li_status;
    }
    
    void reassignPopupMenuElems() {                
        m_anywhere.hidePopupMenuItem("New");
        m_anywhere.hidePopupMenuItem("Search");
        m_anywhere.hidePopupMenuItem("Open");

        m_anywhere.hidePopupMenuItem("Save As");
        m_anywhere.hidePopupMenuItem("Copy Ind");
        m_anywhere.hidePopupMenuItem("Paste Ind");
        m_anywhere.hidePopupMenuItem("Edit Sym");
        m_anywhere.hidePopupMenuItem("About Progeny");
        


        MenuElement[] l_elems = m_anywhere.getPopupMenuElements();
        for (int xx = 0; xx < l_elems.length; xx++) {
            MenuElement elem = l_elems[xx];
            Component comp = elem.getComponent();
            if (comp instanceof JMenuItem) {
                JMenuItem l_item = (JMenuItem)comp;
                String ls_name = l_item.getText();//.getAction().get.getName();
                if ("Save".equalsIgnoreCase(ls_name)) {
                //    Action l_action = l_item.getAction();
                    l_item.setAction(new AbstractAction("Save") {
                        public void actionPerformed(ActionEvent e) {
                            doOnSave();
                        }                        
                    });
                }                
            }
        }
    }
         
         
    /**
     * Adds a menu bar and its corresponsing pull down menu to the Applet, replicating most of the actions that'
     * ar found on the Pedigree toolbar
     */
    void addMenu(JToolBar tb) {
        JMenu menu = new JMenu("Pedigree");
        JMenuBar menubar = new JMenuBar();
        JMenuItem item;
        
        menu.setMnemonic(KeyEvent.VK_P);
        menu.setFont(new Font(getFont().getName(), Font.PLAIN, 12));
        Component buttons[] = tb.getComponents();
        for (int i = 0; i < tb.getComponentCount(); i++) {
            Component button = buttons[i];
            if (button != null && button instanceof JButton) {
                JButton bt = (JButton) button;
                String ls_short = (String)bt.getAction().getValue(bt.getAction().SHORT_DESCRIPTION);
                if (bt.getAction().getValue(bt.getAction().SHORT_DESCRIPTION).equals("Create New Pedigree")) {
                    item = new JMenuItem("New Pedigree");
                    item.setFont(new Font(getFont().getName(), Font.PLAIN, 11));
                    ActionListener[] listeners = bt.getActionListeners();
                    item.addActionListener(listeners.length < 0 ? null : listeners[0]);
                    menu.add(item);
                } else if (bt.getAction().getValue(bt.getAction().SHORT_DESCRIPTION).equals("Print Pedigree")) {
                    //Add Legend Setup dialog to menu
                    item = new JMenuItem("Print");
                    item.setFont(new Font(getFont().getName(), Font.PLAIN, 11));
                    item.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
                            EventQueue.invokeLater(new Runnable() {
                                public void run() {
                                    m_anywhere.printPedigree(true);
                                }
                            });
                        }
                    });
                    menu.add(item);
                } else if (ls_short.startsWith("Search") || ls_short.startsWith("Help")) {
                    //else if (bt.getAction().getValue(bt.getAction().SHORT_DESCRIPTION).equals("Search for Individuals") ||
                    //bt.getAction().getValue(bt.getAction().SHORT_DESCRIPTION).equals("Help"))
                    //ignore
                } else {
                    item = new JMenuItem((String)bt.getAction().getValue(Action.SHORT_DESCRIPTION));
                    item.setFont(new Font(getFont().getName(), Font.PLAIN, 11));
                    ActionListener[] listeners = bt.getActionListeners();
                    item.addActionListener(listeners.length < 0 ? null : listeners[0]);
                    menu.add(item);
                }
            }
        }
        
        //Add Properties Dialog to menu
        item = new JMenuItem("View/Edit Properties");
        item.setFont(new Font(getFont().getName(), Font.PLAIN, 11));
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                EventQueue.invokeLater(new Runnable() {
                    public void run() {
                        m_anywhere.showPropertiesDialog(true);
                    }
                });
            }
        });
        menu.add(item);
        
        //Add Legend Setup dialog to menu
        item = new JMenuItem("Edit Legend");
        item.setFont(new Font(getFont().getName(), Font.PLAIN, 11));
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                EventQueue.invokeLater(new Runnable() {
                    public void run() {
                        m_anywhere.showLegendDialog(true);
                    }
                });
            }
        });
        menu.add(item);
        
        menubar.add(menu);
        setJMenuBar(menubar);
    }
    
    
    
    

    private void delay(int time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException ie) {
        }
    }

    public void start() {
        if (!ib_started) {//execute init() again since we have returned to the page
            ib_started = true;
            delay(500);
            runner = new Thread(this);
            runner.start();
        }
    }
    
    
    /**
     * Stop the applet. This kills the JVM and sometimes the browser as well.
     */
    public void stop() {           
        stopApplet();
    }


    void sendAppletCloseEvent() {
         ObjectInputStream ois = null;
        HttpURLConnection conn  = null;
        try {
            String params = "";
            conn = getServletURLHttpGET(("ACTION_CLOSE_APPLET_WINDOW"), params);


            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
        } catch (EOFException eof) {
        } catch (Exception exc) {
        } finally {
             closeInOutStreams(ois, null, conn);
        }
    }

     public void stopApplet() {
        try {
            sendAppletCloseEvent();
            ib_stop = true;
            ib_inited = false;
            int i = 0;
            while(ib_events_thread_running && ++i < 10){}

            m_anywhere.dispose();
            m_anywhere = null;
            runner = null;
            m_threadExecutor.shutdown(); // shutdown worker threads
            m_threadExecutor = null;            
            m_getEventsURL = null;
        } catch (Exception se) {
        }
    }
    
   
    /**
     * Destroy the applet. This kills the JVM and sometimes the browser as well.
     */
    public void destroy() {
        stopApplet();
        System.setProperty("com.objex.xml.parser", null);
    }
    

    /**
     * Run the Applet thread. Runs a new thread of this Applet and creates a template m_anywhere. If the user was working on
     * a m_anywhere in the last 1 hour and left the page, then the last m_anywhere would still be in the cache and would be
     * brought up automatically for the user to re-edit. If the cached m_anywhere is older than one hour then it will not be brought
     * up. In that case a template or nuclear m_anywhere is created with two parents and a child.
     */
    public void run() {
        if (ib_running_as_applet) {            
            String ls_xml_string = getXMLString();
            if (ls_xml_string != null) {
                try {
                   ib_importing = true;
                   this.m_anywhere.importXMLString(ls_xml_string);                   
                   //getPedigreeLock();
                   ib_importing = false;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            try {
                runner.join(1);
            } catch (InterruptedException ie) {
            }
        }
    }
    
    
    
    
    /**
     * Use this function to send a double click event to the user. This is requeired to pass the DoubleClick event details to the GWT application inside which this applet is running. Unfortunately there is no easy
     * way (short of cranking JS code, and even then only maybe) to pass events between an applet and GWT.
     */
    private void fireIndividualDoubleClicked(Individual a_ind) {
        HttpURLConnection conn  = null;
        ObjectInputStream ois  = null;
        try {            
            if (a_ind == null) {
                JOptionPane.showMessageDialog(this, "No person selected -- cannot open IDS", "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
                return;
            }
            int li_upn = Integer.parseInt(a_ind.getUpn());
            Integer li_server_upn = m_upn_crossref.get(li_upn);
            if (li_server_upn == null) {
                li_server_upn = li_upn;
            }
            String params = "&UPN=" + li_server_upn;
            conn = getServletURLHttpGET("ACTION_ADD_IDSEVENT", params);
            
            
            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            if (response instanceof String) {
                String ls_added = (String)response;
                if ("1".equalsIgnoreCase(ls_added)) {
                    //success
                    return;
                } else {
                    //failure
                }
            }            
        } catch (EOFException eof) {
            //do nothing
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
            this.closeInOutStreams(ois, null, conn);
        }
        JOptionPane.showMessageDialog(this, "Failed to open datasheet for selected person " + STANDARD_MESSAGE_DUE_TO, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
    }
    
    
    
    public String getXMLString() {
        ObjectInputStream ois = null;
        HttpURLConnection conn  = null;        
        try {            
            String params = "";
            conn = getServletURLHttpGET("ACTION_READ_PEDIGREE", params);
                      
            ib_xml_read_pending = true;
            new Thread(readXMLRunnable).start();
            InputStream in = new BufferedInputStream(new ProgressMonitorInputStream(m_anywhere.m_canvas,  new Object[]{"Fetching pedigree data", "Reading"}, conn.getInputStream()));
            ois = new ObjectInputStream(in);

            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            String xml = (String)response;
            return xml;
        } catch (EOFException eof) {
            eof.printStackTrace();
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
            ib_xml_read_pending = false;
            if (m_xmlread_progress_bar != null) {
                try {
                    m_xmlread_progress_bar.setFinished("");
                } catch (Throwable t) {}
            }
            this.closeInOutStreams(ois, null, conn);
        }
        ib_error = true;
        JOptionPane.showMessageDialog(this, "Failed to read pedigree from server", "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return null;
    }
    
    
    void restoreProgenyProperties() {
        m_anywhere.setShowgrid(progeny_properties.get("showgrid"));
        m_anywhere.setSnaptogrid(progeny_properties.get("snapgrid"));
        m_anywhere.setShowpagebreaks(progeny_properties.get("showpagebreaks"));
        m_anywhere.setShowfooter(progeny_properties.get("showfooter"));
        m_anywhere.setShowheader(progeny_properties.get("showheader"));
        m_anywhere.setAutodraw(progeny_properties.get("autodraw"));
        m_anywhere.setLivedragging(progeny_properties.get("livedragging"));
        m_anywhere.setShowlegend(progeny_properties.get("showlegend"));
        m_anywhere.setOneclickadd(progeny_properties.get("oneclickadd"));
        m_anywhere.setShowSubtextLegend(progeny_properties.get("showsubtextlegend"));
        //m_anywhere.setUseStandardProbandArrow(progeny_properties.get("standardprobandarrow"));
        //m_anywhere.setProbandArrowPos(progeny_properties.get("probandarrowpos"));
        m_anywhere.setShowhaplotypes(progeny_properties.get("showhaplotypes"));
    }
    
     private ImportListener m_import_Listener = new ImportListener() {

        public void preparsingImportFile(ImportEvent evt) {
        }

        public void importAborted(ImportEvent evt) {
            ib_importing = false;
            ib_error = true;
            JOptionPane.showMessageDialog(m_anywhere.m_canvas, evt.getMessage(), "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        }

        public void importFinished(ImportEvent evt) {
            ib_importing = false;
            try {
                m_anywhere.getLegend().setShowHiddenItems(false);
                m_anywhere.updateSubtext();
                m_anywhere.updateSymbols();                
                restoreProgenyProperties();

            } catch (Exception e) {
                ib_smartdrawon_import = false;
                e.printStackTrace();
            }
        }

        public void individualImported(ImportEvent evt) {
        }

        public void importTriggered(ImportEvent evt) {
            ib_importing = true;
        }
    };
            
          
  
    
            
    
    
    protected void connectIndividuals(int ai_toupn, int ai_upn, RELATIONSHIP ai_rel) {
        ObjectInputStream ois = null;
        HttpURLConnection conn  = null;
        try {            
            String params = "&TOUPN=" + ai_toupn;
            params  += "&CONNECTUPN=" + ai_upn;
            params  += "&RELATIONSHIP_TYPE=" + ai_rel.getType();            
            conn = getServletURLHttpGET(("ACTION_CONNECT_INDIVIDUALS"), params);  
            
            
            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;            
            switch(li_error_code) {
                case 0://success       
                    synchronized(ib_changed) {
                        ib_changed = true; //back to true
                    }
                    return;
                default:
                    ib_stale_pedigree = true;
                    break;
            }                        
        } catch (EOFException eof) {            
        } catch (Exception exc) {
            ib_stale_pedigree = true;
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, null, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to link individuals " + STANDARD_MESSAGE_DUE_TO,
                                                          STANDARD_MESS_CANNOT_SAVE}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }
    
    
    
    
    
    protected boolean moveIndividuals() {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {
            String queryString = "&WHO=APPLET";             
            queryString += "&FAMILY_ID="+ii_familyid;
            queryString += "&JSESSIONID=" + this.m_JSESSIONID;
            queryString += ("&ACTION=ACTION_MOVE_INDIVIDUALS");
            queryString += "&UID=" + ii_user_token;                      
            //create http connection 
            conn = getServletURLHttpPOST();                        
            
            //attach body of post 
            oos = new ObjectOutputStream(new BufferedOutputStream(conn.getOutputStream()));
            int li_count = m_anywhere.getCount();
            Iterator<Individual> l_inds = m_anywhere.getFamily().getMembers().values().iterator();
            String ls_upns= "";            
            String ls_xcoords = "";            
            String ls_ycoords = "";            
            for (int xx = 0; l_inds.hasNext(); xx++) {
                Individual l_ind = l_inds.next();
                int li_upn = Integer.parseInt(l_ind.getUpn());
                Integer li_serverupn = m_upn_crossref.get(li_upn);
                if (li_serverupn == null) {
                    li_serverupn = li_upn;
                }
                switch (xx) {
                    case 0://first one
                        ls_upns += (li_serverupn);
                        ls_xcoords += l_ind.getX();
                        ls_ycoords += l_ind.getY();
                        break;
                    default://rest -- precede with comma
                        ls_upns += ("," + li_serverupn);
                        ls_xcoords += "," + l_ind.getX();
                        ls_ycoords += "," + l_ind.getY();
                        break;
                }
            }
            queryString += "&UPNS=" + URLEncoder.encode(ls_upns, "UTF-8"); 
            queryString += "&XCOORDS=" + URLEncoder.encode(ls_xcoords, "UTF-8"); 
            queryString += "&YCOORDS=" + URLEncoder.encode(ls_ycoords, "UTF-8");                  
            oos.writeObject(queryString);
            oos.flush();
                                   
            
            //Now get the response from server and Read the input stream from server and get the array of data for display and/or manipulation
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));            
            Object response = ois.readObject();
            int li_error_code = (Integer)response;           
            switch(li_error_code) {
                case 0://success                           
                    return true;
                default:                    
                    break;
            }                        
        } catch (EOFException eof) {            
        } catch (Exception exc) {            
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change locations of selected individual(s) " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return false;                       
    }
    
    
    
    protected void changeGender(GenderChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {            
            int li_upn = Integer.parseInt(event.getIndividual().getUpn());
            Integer li_server_upn = m_upn_crossref.get(li_upn);
                if (li_server_upn == null) {
                    li_server_upn = li_upn;
                }
            String params = "&UPN=" + li_server_upn;
            params += (SPACE + "&GENDER_NEW=" + event.getTo().getIntValue());
            params += (SPACE + "&GENDER_OLD=" + event.getFrom().getIntValue());
            conn = getServletURLHttpGET("ACTION_CHANGE_GENDER", params);            
            
            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;            
            switch(li_error_code) {
                case 0://success        
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    ib_stale_pedigree = true;
                    break;
            }                        
        } catch (EOFException eof) {            
        } catch (Exception exc) {
            ib_stale_pedigree = true;
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the gender of selected person " + STANDARD_MESSAGE_DUE_TO,
                                                         STANDARD_MESSAGE_PED_WILLNOTSAVE}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }


    protected URL getEventsURL(String as_action) throws Exception {
        URL page = m_page == null ? getCodeBase() : m_page;
        String protocol = page.getProtocol();
        String host = page.getHost();
        int port = page.getPort();
        String servlet = "" + is_application_context + "/progenyrpcservice.html";

        servlet += "?WHO=Applet";
        servlet += "&FAMILY_ID=" + this.ii_familyid;
        servlet += "&PARAM_FOLDERID=" + this.ii_folderid;
        servlet += "&JSESSIONID=" + this.m_JSESSIONID;
        servlet += ("&ACTION=" + as_action);
        servlet += "&UID=" + this.ii_user_token;

        URL servletURL = new URL(protocol, host, port, servlet);
        return servletURL;
    }
    
    protected HttpURLConnection getServletURLHttpGET(String as_action, String ... as_params) throws Exception {
        if (context == null) {
            return getServletURLHttpGETStatic(as_action, as_params);
        }
        URL page = m_page == null ? getCodeBase() : m_page;
            //URL page = getCodeBase();
            String protocol = page.getProtocol();
            String host = page.getHost();
            int port = page.getPort();
            String servlet = "" + is_application_context + "/progenyrpcservice.html";
            servlet += "?WHO=Applet";
            servlet += "&FAMILY_ID="+this.ii_familyid;
            servlet += "&JSESSIONID=" + this.m_JSESSIONID;
            servlet += "&PARAM_FOLDERID="+this.ii_folderid;
            servlet += ("&ACTION=" + as_action);
            servlet += "&UID=" + this.ii_user_token;
            
            for (String ls_param : as_params) {
                servlet += ls_param;
            }
            
            URL servletURL = new URL(protocol, host, port, servlet);              
            HttpURLConnection conn = (HttpURLConnection)servletURL.openConnection();
            if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection conns = (HttpsURLConnection) conn;
                conns.setHostnameVerifier(new HostnameVerifier() {
                    public boolean verify(String host, SSLSession session) {
                        return true;
                    }
                });
            }
            //m_Get = conn;
            conn.setRequestMethod("GET");            
            conn.setUseCaches(false);            
            conn.setDoInput(true);
            conn.setConnectTimeout(180 * 1000);
            return conn;
    }

    URL m_Post;//, m_Get;
    //URL uRL;
    URL m_page;
    protected HttpURLConnection getServletURLHttpPOST() throws Exception {
            if (context == null) {
                return getServletURLHttpPOSTStatic();
            }            
            URL page = m_page == null ? getCodeBase() : m_page;
            String protocol = page.getProtocol();
            String host = page.getHost();
            int port = page.getPort();

            String servlet = "" + is_application_context + "/progenyrpcservice.html";

            //if (m_Post == null) {
                URL servletURL = new URL(protocol, host, port, servlet);
              //  m_Post = servletURL;
            //}
            HttpURLConnection conn = (HttpURLConnection)servletURL.openConnection();
            if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection conns = (HttpsURLConnection) conn;
                 conns.setHostnameVerifier(new HostnameVerifier() {
                    public boolean verify(String host, SSLSession session) {
                        return true;
                    }
                });
            }            
            conn.setRequestMethod("POST");
            conn.setUseCaches(false);
            conn.setDoOutput(true); //need this in order to be able to write to the output stream
            conn.setDoInput(true);
            conn.setConnectTimeout(180 * 1000);
            return conn;
    }
    
    protected void setProperty(IndividualPropertyChangeEvent event, String as_function) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {                        
            int li_upn = Integer.parseInt(event.getIndividual().getUpn());
            Integer li_server_upn = m_upn_crossref.get(li_upn);
            if (li_server_upn == null) {
                li_server_upn = li_upn;
            }
            String params = "&UPN=" + li_server_upn;
            Boolean lb_new = (Boolean)event.getNewValue();
            Boolean lb_old = (Boolean)event.getOldValue();
            params += (SPACE + "&VALUE_NEW=" + (lb_new ? 1: 0));
            params += (SPACE + "&VALUE_OLD=" + (lb_old ? 1 : 0));
            params += (SPACE + "&FUNCTION=" + as_function);            
            conn = getServletURLHttpGET("ACTION_CHANGE_PROPERTY", params);                                     
            
            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;            
            switch(li_error_code) {
                case 0://success   
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:                    
                    break;
            }                        
        } catch (EOFException eof) {            
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change status of individual " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }
    
    
    
    protected void setMarkedBy(IndividualPropertyChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {                        
            int li_upn = Integer.parseInt(event.getIndividual().getUpn());
            Integer li_server_upn = m_upn_crossref.get(li_upn);
            if (li_server_upn == null) {
                li_server_upn = li_upn;
            }
            String params = "&UPN=" + li_server_upn;
            String lb_new = (String)event.getNewValue();
            String lb_old = (String)event.getOldValue();
            params += (SPACE + "&VALUE_NEW=" + URLEncoder.encode(lb_new, "UTF-8"));
            params += (SPACE + "&VALUE_OLD=" + URLEncoder.encode(lb_old, "UTF-8"));
            params += (SPACE + "&FUNCTION=ACTION_SETMARKEDBY");
            conn = getServletURLHttpGET("ACTION_CHANGE_PROPERTY", params);                        
            
            
            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;            
            switch(li_error_code) {
                case 0://success                    
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:                    
                    break;
            }                        
        } catch (EOFException eof) {            
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the marked by text for the selected of individual " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }
    
    
    
    protected void setIconText(IndividualPropertyChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {                        
            int li_upn = Integer.parseInt(event.getIndividual().getUpn());
            Integer li_server_upn = m_upn_crossref.get(li_upn);
            if (li_server_upn == null) {
                li_server_upn = li_upn;
            }
            String params = "&UPN=" + li_server_upn;
            String lb_new = (String)event.getNewValue();
            String lb_old = (String)event.getOldValue();
            params += (SPACE + "&VALUE_NEW=" + URLEncoder.encode(lb_new, "UTF-8"));
            params += (SPACE + "&VALUE_OLD=" + URLEncoder.encode(lb_old, "UTF-8"));
            params += (SPACE + "&FUNCTION=ACTION_SETICONTEXT");
            conn = getServletURLHttpGET("ACTION_CHANGE_PROPERTY", params);
            
            
            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;            
            switch(li_error_code) {
                case 0://success
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    break;
            }                        
        } catch (EOFException eof) {            
        } catch (Exception exc) {
            exc.printStackTrace();
        }
        finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the icontext for the selected of individual " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }
    
    

    private void doOnSS() {
        HttpURLConnection conn  = null;
        ObjectInputStream ois  = null;
        try {
            String params = "";
            conn = getServletURLHttpGET("ACTION_ADD_SSEVENT", params);
            
            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            if (response instanceof String) {
                String ls_added = (String)response;
                if ("1".equalsIgnoreCase(ls_added)) {
                    //success
                    return;
                } else {
                    //failure
                }
            }
        } catch (EOFException eof) {
            //do nothing
        } catch (Exception exc) {
        } finally {
            this.closeInOutStreams(ois, null, conn);
        }
        JOptionPane.showMessageDialog(this, "Failed to open spreadsheet " + STANDARD_MESSAGE_DUE_TO, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
    }
    
    public void doOnSave() {
        Runnable task = new RhinoCommunicationTask("save pedigree task") {
            public void run() {
                try {
                    boolean save = true;
                    if (ib_smartdraw) {//was smartdrawn -- must update server xy positions to reflect client before saving
                        save = moveIndividuals();
                    }
                    if (save) {
                        savePedigreeXMLString(true);
                    }
                } catch (Exception exc) {
                }
            }
        };
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }
    
    
    
    

    ////////////////////////////////////////Relationship Listener////////////////////////////////
    public void onConnected(final RelationshipConnectionEvent event) {
        synchronized(ib_changed) {
            ib_changed = true; //back to true
        }
        Runnable task = new RhinoCommunicationTask("connect relationship task") {

            public void run() {
                int li_toperson = Integer.parseInt(event.getToIndividual().getUpn()), li_connectperson = Integer.parseInt(event.getConnectIndividual().getUpn());
                Integer li_newtoperson = m_upn_crossref.get(li_toperson);
                if (li_newtoperson == null) {
                    li_newtoperson = li_toperson;
                }
                Integer li_newconnectperson = m_upn_crossref.get(li_connectperson);
                if (li_newconnectperson == null) {
                    li_newconnectperson = li_connectperson;
                }
                connectIndividuals(li_newtoperson, li_newconnectperson, event.getRelType());
            }
        };
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }
    
    
    public void onDisconnected(final RelationshipDeleteEvent event) {
        synchronized(ib_changed) {
            ib_changed = true; //back to true
        }
        Runnable task = new RhinoCommunicationTask("disconnect relationship task") {
            public void run() {
                int li_person1 = Integer.parseInt(event.person1.getUpn()), 
                    li_person2 = event.person2 == null ? 0 : Integer.parseInt(event.person2.getUpn());
                Integer li_newperson1 = m_upn_crossref.get(li_person1);
                if (li_newperson1 == null) {
                    li_newperson1 = li_person1;
                }
                Integer li_newperson2 = m_upn_crossref.get(li_person2);
                if (li_newperson2 == null) {
                    li_newperson2 = li_person2;
                }
                breakRelationshipLine(li_newperson1, li_newperson2, event.relType);
            }
        };
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }
    
    
    
    
    ////////////////////////////////////////Individual Listener //////////////////////////////////////////////////   
    public void onDragged(final DragEvent event) {
        synchronized(ib_changed) {
            ib_changed = true; //back to true
        }
        Runnable task = new RhinoCommunicationTask("move individual locations task") {
            public void run() {
               moveIndividuals(); //tell server what the client is seeing in terms of positions
                //doOnDragEvent(event);
            }
        };
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }
    
    public void onGenderChanged(final GenderChangeEvent event) {
        synchronized(ib_changed) {
            ib_changed = true; //back to true
        }
        Runnable task = new RhinoCommunicationTask("change person gender task") {
            public void run() {                
                changeGender(event);
            }
        };        
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }
    
    
    public void onPropertyChanged(final IndividualPropertyChangeEvent event) {
        synchronized(ib_changed) {
            ib_changed = true; //back to true
        }
        Runnable task = new RhinoCommunicationTask("change individual property task") {
            public void run() {
                switch (event.getProperty()) {
                    case DECEASED_PROPERTY:
                        setProperty(event, "ACTION_SETDECEASED_STATUS");                        
                        break;
                    case PROBAND_PROPERTY:
                        setProperty(event, "ACTION_SETPROBAND_STATUS");
                        break;
                    case NOISSUE_PROPERTY:                        
                        setProperty(event, "ACTION_SETNOISSUE_STATUS");
                        break;
                    case INFERTILE_PROPERTY:
                        setProperty(event, "ACTION_SETINFERTILE_STATUS");
                        break;
                    case SAB_PROPERTY:
                        setProperty(event, "ACTION_SETSAB_STATUS");
                        break;
                    case ADOPTEDIN_PROPERTY:
                        setProperty(event, "ACTION_SETADOPTEDIN_STATUS");
                        break;
                    case ADOPTEDOUT_PROPERTY:
                        setProperty(event, "ACTION_SETADOPTEDOUT_STATUS");
                        break;
                    case MARKEDBY_PROPERTY:          
                        setMarkedBy(event);
                        break;
                    case ICONTEXT_PROPERTY:
                        setIconText(event);
                        break;
                }
            }
        };
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }
    
    
    
    
    
    protected boolean doOnDragEvent(DragEvent event) {
        
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {
            String queryString = "&WHO=APPLET";             
            queryString += "&FAMILY_ID="+ii_familyid;
            queryString += "&JSESSIONID=" + this.m_JSESSIONID;
            queryString += ("&ACTION=ACTION_DRAG_INDIVIDUALS");
            queryString += "&UID=" + ii_user_token;                      
            //create http connection 
            conn = getServletURLHttpPOST();                        
            
            //attach body of post 
            oos = new ObjectOutputStream(new BufferedOutputStream(conn.getOutputStream()));            
            Individual[] l_inds = event.getDraggedIndividuals();
            String ls_upns= "";                        
            for (int xx = 0; xx < l_inds.length; xx++) {
                Individual l_ind = l_inds[xx];
                int li_upn = Integer.parseInt(l_ind.getUpn());
                Integer li_serverupn = m_upn_crossref.get(li_upn);
                if (li_serverupn == null) {
                    li_serverupn = li_upn;
                }
                switch (xx) {
                    case 0://first one
                        ls_upns += (li_serverupn);                        
                        break;
                    default://rest -- precede with comma
                        ls_upns += ("," + li_serverupn);
                        break;
                }
            }
            queryString += "&UPNS=" + URLEncoder.encode(ls_upns, "UTF-8"); 
            queryString += "&XCOORDS_DELTA=" + URLEncoder.encode(""+event.getDeltaX(), "UTF-8"); 
            queryString += "&YCOORDS_DELTA=" + URLEncoder.encode(""+event.getDeltaY(), "UTF-8");                  
            oos.writeObject(queryString);
            oos.flush();
                                   
            
            //Now get the response from server and Read the input stream from server and get the array of data for display and/or manipulation
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));            
            Object response = ois.readObject();
            int li_error_code = (Integer)response;
            //////////////////////////
            switch(li_error_code) {
                case 0://success
                    //get the next object which must be a list containing UPN array, xcoords array and ycoords array
                    java.util.List list = (java.util.List)ois.readObject();
                    if (list.size()  == 0) {
                        return false;//something failed
                    }
                    String lm_upns[] = ((String)list.get(0)).split(",");
                    String lm_x[] = ((String)list.get(1)).split(",");
                    String lm_y[] = ((String)list.get(2)).split(",");
                    double lm_xd[] = new double[lm_upns.length];
                    double lm_yd[] = new double[lm_upns.length];
                    String lm_local_upns[] = new String[lm_upns.length];
                    for (int xx = 0; xx < lm_upns.length; xx++) {
                        String ls_upn = getClientUPN(lm_upns[xx]);
                        if (ls_upn == null) {
                            ls_upn = lm_upns[xx];
                        }
                        lm_local_upns[xx] = ls_upn;
                        lm_xd[xx] = Double.parseDouble(lm_x[xx]);
                        lm_yd[xx] = Double.parseDouble(lm_y[xx]);
                    }
                    m_anywhere.importSmartDrawPositions(lm_local_upns, lm_xd, lm_yd);
                    m_anywhere.clearRepaintArea();
                    return true;
                default:
                    break;
            }
            //////////////////////////
            
            
            switch(li_error_code) {
                case 0://success       
                    ib_moved = false;
                    return true;
                default:
  //                  ib_stale_pedigree = true;
                    break;
            }                        
        } catch (EOFException eof) {            
        } catch (Exception exc) {
            exc.printStackTrace();
//            ib_stale_pedigree = true;
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the locations of selected individual(s) " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return false;                       
    }
    

    
    
    
    protected void breakRelationshipLine(int ai_person1, int ai_person2, int ai_rel) {        
        ObjectInputStream ois = null;
        HttpURLConnection conn  = null;
        try {
            String params = "&PERSON1=" + ai_person1;
            params  += "&PERSON2=" + ai_person2;
            params  += "&RELATIONSHIP_TYPE=" + ai_rel;            
            conn = getServletURLHttpGET("ACTION_DISCONNECT_INDIVIDUALS", params);  
            
            
            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));

            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;            
            switch(li_error_code) {
                case 0://success       
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    ib_stale_pedigree = true;
                    break;
            }                        
        } catch (EOFException eof) {            
        } catch (Exception exc) {
            ib_stale_pedigree = true;
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, null, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to break the relationship line " + STANDARD_MESSAGE_DUE_TO,
                                                         STANDARD_MESSAGE_PED_WILLNOTSAVE}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }



    void addRelation(Individual a_added_individual, Individual a_to_individual) {
        if (a_added_individual == null) {
            return;
        }
        ObjectInputStream ois = null;
        HttpURLConnection conn  = null;
        try {
            int li_spouse_status =  0;
            int li_toperson = 0;
            int li_relation = 0;
            if (a_to_individual != null) {
                li_toperson = Integer.parseInt(a_to_individual.getUpn());
                if (a_added_individual.isParentOf(a_to_individual, true)) {
                    li_relation = a_added_individual.isMale() ? ProgenyAnywhereWrapper.FATHER : ProgenyAnywhereWrapper.MOTHER;
                }
                if (li_relation == 0) {
                    Individual l_toperson = a_to_individual;
                    if (l_toperson.isSiblingOf(a_added_individual, true)) {
                        li_relation = (a_added_individual.isFemale() ? ProgenyAnywhereWrapper.SISTER : ProgenyAnywhereWrapper.BROTHER);
                    } else {
                        if (l_toperson.isParentOf(a_added_individual, true)) {
                        //if (a_added_individual.isChildOf(l_toperson)) {
                            li_relation = (a_added_individual.isFemale() ? ProgenyAnywhereWrapper.DAUGHTER : ProgenyAnywhereWrapper.SON);
                        } else {
                            if (a_added_individual.isSpouseOf(l_toperson)) {
                                li_relation = (ProgenyAnywhereWrapper.SPOUSE);
                                li_spouse_status = getSpouseRelationshipStatus(l_toperson, a_added_individual);
                            }
                        }
                    }
                    li_toperson = Integer.parseInt(l_toperson.getUpn());
                }
            }

            Integer li_server_upn = m_upn_crossref.get(li_toperson);
            String params = "&UPN="+(li_server_upn == null ? li_toperson : li_server_upn);//RHINO UPN -- may be different from local UPN
            params += "&PARAM_GENDER=" + (a_added_individual.isMale() ? 1 : 0);
            params += "&PARAM_DECEASED=" + (a_added_individual.isDeceased() ? 1 : 0);
            params += "&PARAM_RELATION=" + (li_relation);
            if (li_relation == ProgenyAnywhereWrapper.SPOUSE) {
                params += "&PARAM_SPOUSE_STATUS=" + li_spouse_status;
            }
            conn = getServletURLHttpGET("ACTION_ADD_RELATION", params);

            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            Integer li_newupn = (Integer)response;
            if (li_newupn > 0) {
                m_upn_crossref.put(Integer.parseInt(a_added_individual.getUpn()), li_newupn);
                return;
            } else {
                ib_stale_pedigree = true;
                JOptionPane.showMessageDialog(this, new String[]{"Failed to add a relative to selected individual " + STANDARD_MESSAGE_DUE_TO, STANDARD_MESS_CANNOT_SAVE}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
                return;
            }
        } catch (EOFException eof) {
            //do nothing
        } catch (Exception exc) {
            ib_stale_pedigree = true;
        } finally {
             closeInOutStreams(ois, null, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to add a relative to selected individual " + STANDARD_MESSAGE_DUE_TO, STANDARD_MESS_CANNOT_SAVE}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
    }


    

    public void onIndividualsDeleted(final IndividualsDeleteEvent event) {
        if (ib_importing) {
            return;
        }
        synchronized(ib_changed) {
            ib_changed = true; //back to true
        }
        Runnable task = new RhinoCommunicationTask("delete persons task") {
            public void run() {
                deleteRelations(event.deleted);
            }
        };
       //TODO if connected to a server then enable line  m_threadExecutor.execute(task);
        
    }



    void deleteRelations(Individual[] a_delete_individuals) {
        if (a_delete_individuals == null) {
            return;
        }
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        HttpURLConnection conn  = null;

        try {
            String queryString = "&WHO=APPLET";
            queryString += "&FAMILY_ID="+ii_familyid;
            queryString += "&JSESSIONID=" + this.m_JSESSIONID;
            queryString += ("&ACTION=ACTION_DELETE_PERSONS");
            queryString += "&UID=" + ii_user_token;
            queryString += "&PARAM_FOLDERID="+this.ii_folderid;

            //create http connection
            conn = getServletURLHttpPOST();

            //attach body of post
            oos = new ObjectOutputStream(new BufferedOutputStream(conn.getOutputStream()));
            Individual[] l_inds = a_delete_individuals;
            String ls_upns= "";
            for (int xx = 0; xx < l_inds.length; xx++) {
                Individual l_ind = l_inds[xx];
                int li_upn = Integer.parseInt(l_ind.getUpn());
                Integer li_serverupn = m_upn_crossref.get(li_upn);
                if (li_serverupn == null) {
                    li_serverupn = li_upn;
                }
                switch (xx) {
                    case 0://first one
                        ls_upns += (li_serverupn);
                        break;
                    default://rest -- precede with comma
                        ls_upns += ("," + li_serverupn);
                        break;
                }
            }
            queryString += "&UPNS=" + URLEncoder.encode(ls_upns, "UTF-8");
            oos.writeObject(queryString);
            oos.flush();


            //Now get the response from server and Read the input stream from server and get the array of data for display and/or manipulation
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            Object response = ois.readObject();
            int li_error_code = (Integer)response;            
            switch(li_error_code) {
                case 0://success
                    //remove the individuals with those UPNs from the XREF map if they exist
                    for (int xx = 0; xx < l_inds.length; xx++) {
                        Individual l_ind = l_inds[xx];
                        int li_upn = Integer.parseInt(l_ind.getUpn());
                        m_upn_crossref.remove(li_upn);
                    }
                    return;
                default:
                    ib_stale_pedigree = true;
                    break;
            }
        } catch (EOFException eof) {
        } catch (Exception exc) {
            exc.printStackTrace();
            ib_stale_pedigree = true;
        } finally {
            closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to delete individuals from pedigree " + STANDARD_MESSAGE_DUE_TO,
                                                          STANDARD_MESSAGE_PED_WILLNOTSAVE}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
    }




    protected String getClientUPN(String as_serverupn) {
        Iterator<Map.Entry<Integer, Integer>> itr = m_upn_crossref.entrySet().iterator();
        while (itr.hasNext()) {
            Map.Entry l_entry = itr.next();
            if (as_serverupn.equalsIgnoreCase(l_entry.getValue().toString())) {
                return l_entry.getKey() + "";
            }
        }
        return as_serverupn;
    }

     protected int getServerUPN(int ai_client) {
        int li_upn = ai_client;
        Integer li_serverupn = m_upn_crossref.get(li_upn);
        if (li_serverupn == null) {
            li_serverupn = li_upn;
        }

        return li_serverupn;
    }



    public boolean savePedigreeXMLString(boolean ab_show_success) throws Exception {
        ObjectInputStream ois = null;
        HttpURLConnection conn  = null;
        try {
            if (ib_locked) {
                return true; //couldnt have made changes anyway
            }
            if (ib_stale_pedigree) {
                JOptionPane.showMessageDialog(this, new String[]{"The pedigree is in an incosistent state so it cannot be saved"}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
                return false;
            }
            synchronized(ib_changed) {
                ib_changed = false;
            }
            String params = "&FAMILY_NAME="+ URLEncoder.encode(is_familyname, "UTF-8");
            conn = getServletURLHttpGET("ACTION_SAVE_PEDIGREE", params);

            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            Integer li_save = (Integer)response;
            switch (li_save) {
                case -200:
                    JOptionPane.showMessageDialog(this, "Failed to save pedigree because you have no permission to write/change this pedigree", "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
                    return false;
                case 1://break;//saved successfully
                    if (ab_show_success) {
                        String ls_err = ("Pedigree was successfully saved");
                        JOptionPane.showMessageDialog(this, ls_err, "Operation Completed", JOptionPane.INFORMATION_MESSAGE);
                    }
                    return true;
                default:
                    break;
            }
        } catch (EOFException eof) {
           // eof.printStackTrace();
        } catch (Exception exc) {
            exc.printStackTrace();
            synchronized(ib_changed) {
                ib_changed = true; //back to true
            }
            JOptionPane.showMessageDialog(this, "Failed to save pedigree to the database due to database error", "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
            throw exc;
        } finally {
             closeInOutStreams(ois, null, conn);
        }
        return false;
    }












    protected void setPedigreeProperty(PedigreePropertyChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {
            String params = "";
            String ls_newvalue = event.newValue == null ? "" : event.newValue.toString();
            String ls_oldvalue = event.oldValue == null ? "" : event.oldValue.toString();
            if (event.newValue instanceof Double) {
                ls_newvalue = (int)Math.round((Double)event.newValue) + "";                
            } else {
                if (event.newValue instanceof Float) {
                ls_newvalue = (int)Math.round((Float)event.newValue) + "";                
                }
            }
            if (event.oldValue instanceof Double) {
                ls_oldvalue = (int)Math.round((Double)event.oldValue) + "";
            } else {
               if (event.oldValue instanceof Float) {
                   ls_oldvalue = (int)Math.round((Float)event.oldValue) + "";
               }
            }
            switch (event.property) {
                    case SCALE:
                        ls_newvalue = event.newValue == null ? "" : event.newValue.toString();
                        ls_oldvalue = event.oldValue == null ? "" : event.oldValue.toString();
                        break;
                    default:
                        break;
             }
            params += (SPACE + "&VALUE_NEW=" + URLEncoder.encode(ls_newvalue, "UTF-8"));
            params += (SPACE + "&VALUE_OLD=" + URLEncoder.encode(ls_oldvalue, "UTF-8"));
            params += (SPACE + "&PROPERTY=" + event.property.getProperty());
            conn = getServletURLHttpGET("ACTION_CHANGE_PEDIGREE_PROPERTY", params);

            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;
            switch(li_error_code) {
                case 0://success
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    break;
            }
        } catch (EOFException eof) {
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change status of individual " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }



    protected void setPedigreeHeader(PedigreePropertyChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {
            String params = "";
            String lb_new = (String)event.newValue;
            String lb_old = (String)event.oldValue;
            params += (SPACE + "&VALUE_NEW=" + URLEncoder.encode(lb_new, "UTF-8"));
            params += (SPACE + "&VALUE_OLD=" + URLEncoder.encode(lb_old, "UTF-8"));
            params += (SPACE + "&PROPERTY=" + event.property.getProperty());//params += (SPACE + "&FUNCTION=ACTION_SETPEDIGREE_HEADER");
            conn = getServletURLHttpGET("ACTION_CHANGE_PEDIGREE_PROPERTY", params);


            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;
            switch(li_error_code) {
                case 0://success
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    break;
            }
        } catch (EOFException eof) {
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the pedigree header " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }


    protected void setPedigreeFooter(PedigreePropertyChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {
            String params = "";
            String lb_new = (String)event.newValue;
            String lb_old = (String)event.oldValue;
            params += (SPACE + "&VALUE_NEW=" + URLEncoder.encode(lb_new, "UTF-8"));
            params += (SPACE + "&VALUE_OLD=" + URLEncoder.encode(lb_old, "UTF-8"));
            params += (SPACE + "&PROPERTY=" + event.property.getProperty());//params += (SPACE + "&FUNCTION=ACTION_SETPEDIGREE_FOOTER");
            conn = getServletURLHttpGET("ACTION_CHANGE_PEDIGREE_PROPERTY", params);


            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;
            switch(li_error_code) {
                case 0://success
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    break;
            }
        } catch (EOFException eof) {
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the pedigree header " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }


    protected void setPedigreeSubtextFont(PedigreePropertyChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {
            String params = "";
            Font l_font = (Font)event.newValue;
            params += (SPACE + "&FONTNAME=" + URLEncoder.encode(l_font.getFontName(), "UTF-8"));
            params += (SPACE + "&FONTSTYLE=" + URLEncoder.encode(l_font.getStyle()+"", "UTF-8"));
            params += (SPACE + "&FONTSIZE=" + URLEncoder.encode(l_font.getSize()+"", "UTF-8"));
            params += (SPACE + "&PROPERTY=" + event.property.getProperty());//params += (SPACE + "&FUNCTION=ACTION_SETPEDIGREE_FONT");
            conn = getServletURLHttpGET("ACTION_CHANGE_PEDIGREE_PROPERTY", params);


            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;
            switch(li_error_code) {
                case 0://success
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    break;
            }
        } catch (EOFException eof) {
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the pedigree header " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }

    

    public void onPropertyChanged(final PedigreePropertyChangeEvent event) {
        synchronized(ib_changed) {
            ib_changed = true; //back to true
        }
        Runnable task = new RhinoCommunicationTask("change pedigree property task") {
            public void run() {
                switch (event.property) {
                    case HEADER:
                        setPedigreeHeader(event);
                        break;
                    case FOOTER:
                        setPedigreeFooter(event);
                        break;
                    case FONT:
                        setPedigreeSubtextFont(event);
                        break;
                    default:
                        setPedigreeProperty(event);
                        break;
                }
            }
        };
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }


    public void showPalette() {
        m_anywhere.showPaletteDialog(true);
    }



    public void onSpouseRelationshipChanged(final RelationshipChangeEvent event) {
        switch(event.status) {//checkboxes
            case NORMAL_SPOUSAL:
            case DIVORCED_SPOUSAL:
            case SEPARATED_SPOUSAL:
            case CASUAL_SPOUSAL:
                if (!event.set) {
                    return; //really no need to go unsetting because this is done when the set event is sent
                }
                break;
            default:
                break;
        }
        Runnable task = new RhinoCommunicationTask("change spouse relationship task") {
            public void run() {                
                  changeSpouseRel(event);
            }
        };
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }




    protected void changeSpouseRel(RelationshipChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {
            String params = "";
            int li_upn = Integer.parseInt(event.ind.getUpn());
            Integer li_serverupn = m_upn_crossref.get(li_upn);
            if (li_serverupn == null) {
                li_serverupn = li_upn;
            }
            params += "&PERSON=" + URLEncoder.encode(li_serverupn + "", "UTF-8");
            li_upn = Integer.parseInt(event.spouse.getUpn());
            li_serverupn = m_upn_crossref.get(li_upn);
            if (li_serverupn == null) {
                li_serverupn = li_upn;
            }
            params += "&SPOUSE=" + URLEncoder.encode(li_serverupn + "", "UTF-8");           
            params += (SPACE + "&RELATIONSHIP_TYPE=" + URLEncoder.encode(event.status.getType() + "", "UTF-8"));
            params += (SPACE + "&SET=" + URLEncoder.encode(event.set ? "1" : "0", "UTF-8"));
            conn = getServletURLHttpGET("ACTION_CHANGE_SPOUSE_RELATIONSHIP", params);


            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;
            switch(li_error_code) {
                case 0://success
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    break;
            }
        } catch (EOFException eof) {
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the spouse relationship status " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }



    public void onRelationshipChanged(final TwinRelationshipChangeEvent event) {
        if (!event.set) {
             return; //really no need to go unsetting because this is done when the set event is sent
        }
        Runnable task = new RhinoCommunicationTask("change twin relationship task") {
            public void run() {                
                  changeTwinRel(event);
            }
        };
        //TODO if connected to a server then enable line m_threadExecutor.execute(task);
    }




    protected void changeTwinRel(TwinRelationshipChangeEvent event) {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        HttpURLConnection conn  = null;
        try {
            String params = "";
            String ls_twins = "";
            for (int xx = 0; xx < event.twins.length; xx++) {
                int li_upn = Integer.parseInt(event.twins[xx].getUpn());
                Integer li_serverupn = m_upn_crossref.get(li_upn);
                if (li_serverupn == null) {
                    li_serverupn = li_upn;
                }
                switch (xx) {
                    case 0:
                        ls_twins += li_serverupn;
                    default:
                        ls_twins += ("," + li_serverupn);
                        break;
                }
            }
            params += ("&TWINS=" + URLEncoder.encode(ls_twins + "", "UTF-8"));
            params += (SPACE + "&RELATIONSHIP_TYPE=" + URLEncoder.encode(event.status.getType() + "", "UTF-8"));
            params += (SPACE + "&SET=" + URLEncoder.encode(event.set ? "1" : "0", "UTF-8"));
            conn = getServletURLHttpGET("ACTION_CHANGE_TWIN_RELATIONSHIP", params);


            //Now get the response from server
            ois = new ObjectInputStream(new BufferedInputStream(conn.getInputStream()));
            //Read the input stream from server and get the array of data for display and/or manipulation
            Object response = ois.readObject();
            int li_error_code = (Integer)response;
            switch(li_error_code) {
                case 0://success
                    synchronized(ib_changed) {
                       ib_changed = true; //back to true
                    }
                    return;
                default:
                    break;
            }
        } catch (EOFException eof) {
        } catch (Exception exc) {
            exc.printStackTrace();
        } finally {
             closeInOutStreams(ois, oos, conn);
        }
        JOptionPane.showMessageDialog(this, new String[]{"Failed to change the twin relationship status " + STANDARD_MESSAGE_DUE_TO}, "Operation Cancelled", JOptionPane.ERROR_MESSAGE);
        return ;
    }



    
} //end class StudentPageApplet


