import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.event.*;
import java.util.*;
import java.lang.Object.*;
import javax.imageio.ImageIO.*;
import java.awt.image.*;
import javax.imageio.ImageIO;





public class MultiChannel_Movie_Canvas extends CustomCanvas
{
    private String SERVER_URL2 = null;           // initialized in constructor
    private String SERVER_URL3 = null;           // initialized in constructor
    private String SERVER_URL4 = null;           // initialized in constructor
    private String SERVER_URL9 = null;           // initialized in constructor
    private float TACH_SAMPLING_FREQUENCY=-1;    // initialized in init()
    private int NUM_CHANNELS = 0;                // initialized in init()
    protected float SAMPLING_FREQUENCY=-1;         // initialized in init()
    private float TOPPANEL_SECS_PER_PIXEL=-1;    // initialized in init()
    private int MOVIE_PIXEL_OFFSET = 0;          // if movie is running, only increments of signal are drawn in repaint method
    private int MOVIE_SPEED_SCALE;          // changed when rendering speed (playback speed slider) is adjusted
    private long CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    private long CURRENTLY_CLICKED_ANN_INDEX = -1;
    private boolean MOVIE_IS_PLAYING = false; 
    private boolean DRAW_BLANK_CANVAS = false;
    private boolean ADDING_NEW_ANNOTATION = false;
    private boolean DELETING_ANNOTATION = false;
    private Vector movie_buttons = new Vector();
    private Vector browser_buttons = new Vector();
    private String active_annotation = new String();
    private int FIRST_BIN=0;
    private int LAST_BIN=0;
    private long CURRENT_SCAN_INDEX1=0;
    private long CURRENT_SCAN_INDEX2=0;
    private int CURRENT_BIN=-1;
    private String SCAN_MODE = "ANNOT";            // may be "ANNOT" or "HIST"  
    private TxtLabel Transient_Txt = null;
    private int FIFO_DEPTH = 50;                   // N-deep FIFO should match MAX_DEPTH in ScopeCanvas.java
    private String DIRECTION = "F";                // may be "F" for forward or "B" for backward
    private int GRANDPARENT_ACTIVE_10MIN_SEGMENT = 0;

    private long caliper_begin = -1;
    private long caliper_end = -1;
    private long HISTOGRAM_SCAN_LINENUM = -1;
    private long HISTOGRAM_SCAN_INDEX = 0;
    
    protected long START_INDEX = 0;
    protected long TEMP_START_INDEX = 0;
    protected long END_INDEX = 0;
    protected long nsamp = 0;
    protected int ANNOT_ADVANCE = 0;
    protected long next_time = 0;
    protected int X_SCALE;
    protected float Y_SCALE;
    protected Vector active_channel_numbers = new Vector();
    protected Vector annotation_indeces = new Vector();
    protected Vector annotation_values = new Vector();
    protected Vector renderedannotations = new Vector();
    protected Vector signalnames = new Vector(); //holds the text name of each signal TDMA sequenced
    protected DefaultComboBoxModel sigs = new DefaultComboBoxModel();//holds a non-redundant array of signal feed names works with sigvals for visibility collaboration
    protected Vector sigvals = new Vector(); //corresponding "0"-off, or "1"-on, for matching index signal name
    protected Vector nextactiveannottime = new Vector(); //holds the time for the next or prev instance of the desired annotation
    protected TimerInterruptGenerator timer_interrupt_generator = null;  // timer for movie rendering
    protected String signalname = ""; //Set to be the active signal for addition or removal via signal visibilty popup
    protected String anntype;
    protected String dbid;
    protected String recid;
    protected int init_x;
    protected int init_y;
    protected int zoomx;
    protected int zoomy;   
    protected Vector xscalevals = new Vector();
    protected int popup_on_off = 0; //keeps track of refreshing need for popup window(only set once, not on every repaint() call )
    protected JMenu submenu = new JMenu("Signal Visibility");//right-click enabled signal sivisility popup on canvas displaying signals


    

    // CustomCanvas constructor
    public MultiChannel_Movie_Canvas(JLabel label,int gridX, int gridY)
      { 
      this.glob_label = label;
      this.SERVER_URL = null; 
      this.SERVER_URL2 = null;
      this.SERVER_URL3 = null;
      this.SERVER_URL4 = null;
      this.gridx = gridX; 
      this.gridy = gridY;
      init_x = gridX;
      init_y = gridY;
      addMouseListener(this);
      addMouseMotionListener(this);
      setBackground(Color.WHITE);
      setOpaque(true);
      zoomx = 50;
      zoomy = 50;
      addPopupMenu();
      addSubMenutoPopup(this.submenu);
      JCheckBoxMenuItem cbMenuItem = new JCheckBoxMenuItem("TEST");
      cbMenuItem.setState(true);
      submenu.add(cbMenuItem);
      }

  public void load(String URL)
    { 
	// remains to override abstract function from parent
    }

    public void load(String URL, String URL2, String URL9, String annotype, String dbid, String recid)
    { 
	this.SERVER_URL = URL;
	this.SERVER_URL2 = URL2;
	this.SERVER_URL9 = URL9;
	this.anntype = annotype;
	this.dbid = dbid;
	this.recid = recid;

    }

    //public void load(String URL, String URL2, String URL3)
    // {
    //this.SERVER_URL = URL;        // returns number of channels
    //this.SERVER_URL2 = URL2;      // returns signals in interleaved format based on input of which channels to display
    //this.SERVER_URL3 = URL3;
    //}

    //public void load(String URL, String URL2, String URL3, String URL4)
    //{
    //this.SERVER_URL = URL;        // returns number of channels
    //this.SERVER_URL2 = URL2;      // returns signals in interleaved format based on input of which channels to display
    //this.SERVER_URL3 = URL3;
    //this.SERVER_URL4 = URL4;
    //}

  public void add_annot()
    {
	//this.point = null;
	//this.point2 = null;
	//this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
	//this.CURRENTLY_CLICKED_ANN_INDEX = -1;
	//this.ADDING_NEW_ANNOTATION = true;
    }

  public void del_annot()
    {
	//this.point = null;
	//this.point2 = null;
	//this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
	//this.CURRENTLY_CLICKED_ANN_INDEX = -1;
	//this.DELETING_ANNOTATION = true;

    // if we are already over an annotation or if point3 & point4 are not null (indicating multi-delete), then take immediate action
    //if(point != null)
	// {
	//Enumeration enum_ann_indeces = this.annotation_indeces.elements();
	//while(enum_ann_indeces.hasMoreElements()) 
	// {
        //Long currentindex = (Long) enum_ann_indeces.nextElement();
        //int pixeloffset;
        //if(this.X_SCALE < 0)
	//  {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)/-X_SCALE + this.grid_x_threshold);}
        //else
	//  {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)*X_SCALE + this.grid_x_threshold);}
        //if(point.x >= pixeloffset-5 && point.x <= pixeloffset+5)
	//  {
	//  int tmpindex = this.annotation_indeces.indexOf(currentindex);
	//  this.delete_annotation_from_server(currentindex.longValue());
	//  this.annotation_indeces.removeElementAt(tmpindex);
	//  this.annotation_values.removeElementAt(tmpindex);
	//  this.DELETING_ANNOTATION = false;
	//  break;
        //  }
	// }
	//}  

	//if(this.point3 != null && this.point4 != null)
	// {
	//Enumeration enum_ann_indeces = this.annotation_indeces.elements();

       // note: we are doing multiple deletes - cannot perform these deletes within enumeration scan, so store indeces and do delete in separate loop
       //Vector ann_indeces_for_delete = new Vector(); 
 
       //while(enum_ann_indeces.hasMoreElements()) 
       //  {
       //  Long currentindex = (Long) enum_ann_indeces.nextElement();
       //  int pixeloffset;
       //  if(this.X_SCALE < 0)
	//	   {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)/-X_SCALE + this.grid_x_threshold);}
        // else
	//   {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)*X_SCALE + this.grid_x_threshold);}
        // if(pixeloffset > point3.x && pixeloffset < point4.x)
	//   {
        //   ann_indeces_for_delete.addElement(currentindex);
	//   this.delete_annotation_from_server(currentindex.longValue());
        //   }
        // } 
 
	//this.DELETING_ANNOTATION = false;
	//this.point3 = null; this.point4 = null;       
	//int initial_size = ann_indeces_for_delete.size();
	//for(int i=0; i < initial_size; i++)
        // {
        // int tmpindex = this.annotation_indeces.indexOf(ann_indeces_for_delete.elementAt(i));
        // this.annotation_indeces.removeElementAt(tmpindex);
        // this.annotation_values.removeElementAt(tmpindex);
        // }
	//ann_indeces_for_delete.removeAllElements();
	// }

	//this.repaint();
    }
 public void set_end()
    {
        //int counter = 0;
	try
	    {
		URL u6;
		if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
		    {u6 = new URL(this.SERVER_URL9 + "&index=" + this.START_INDEX + "&width=" + -this.X_SCALE*(this.rightx-this.grid_x_threshold) + "&CMD=END" + "&ANNTYPE=" + this.anntype + "&WANTED=" + this.active_annotation);}
		else
		    {u6 = new URL(this.SERVER_URL9 + "&index=" + this.START_INDEX + "&width=" + (this.rightx-this.grid_x_threshold)/this.X_SCALE + "&CMD=END" + "&ANNTYPE=" + this.anntype + "&WANTED=" + this.active_annotation);} 
		URLConnection conn6 = u6.openConnection(); 
		HttpURLConnection httpConn6 = (HttpURLConnection) conn6;
		int responseCode6 = httpConn6.getResponseCode();
		//this.annotation_indeces.removeAllElements();                  // clear the existing annotation buffers
		//this.annotation_values.removeAllElements();
		
		if(responseCode6 == HttpURLConnection.HTTP_OK)
		    {
			InputStream in6 = httpConn6.getInputStream(); 
			Reader reader6 = new InputStreamReader(in6);
			BufferedReader bufferedReader6 = new BufferedReader(reader6);
			String line6;                                       // annotations streamed in two-line pairs, first line is sample # (int), next line is annotation (string)
		
			
			while((line6 = bufferedReader6.readLine()) != null)
			    {
				if(!line6.equals("none"))
				    {
					String tmpval6 = new String(line6);
					//nextactiveannottime.addElement(tmpval6);
					this.next_time  = Long.parseLong(tmpval6.trim());
					//if(counter == 0){
					//   this.END_INDEX = this.next_time;
					//   counter++;
					//}
					//else if(counter == 1){
					    this.nsamp = this.next_time;
					    this.END_INDEX = this.nsamp;    
					//}
					//this.START_INDEX = 16;
				    }
				else
				    {
					//this.START_INDEX = 16;
					
				    }
				
			    }
			bufferedReader6.close();
		    } 
		httpConn6.disconnect();
		
			
	    }
        catch (MalformedURLException e) {System.out.println("Malformed URL:" + e);}
        catch (IOException e) {System.out.println("IOException:" + e);}
	

    }
    //new function implementation to send desired annotation to server script, the server responds with the signal name and time of next instance
  public void next_annot()
    {

	int none = 1;

	try
	    {
		URL u6;
		if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
		    {u6 = new URL(this.SERVER_URL9 + "&index=" + this.START_INDEX + "&width=" + -this.X_SCALE*(this.rightx-this.grid_x_threshold) + "&CMD=ANN" + "&ANNTYPE=" + this.anntype + "&WANTED=" + this.active_annotation);}
		else
		    {u6 = new URL(this.SERVER_URL9 + "&index=" + this.START_INDEX + "&width=" + (this.rightx-this.grid_x_threshold)/this.X_SCALE + "&CMD=ANN" + "&ANNTYPE=" + this.anntype + "&WANTED=" + this.active_annotation);} 
		URLConnection conn6 = u6.openConnection(); 
		HttpURLConnection httpConn6 = (HttpURLConnection) conn6;
		int responseCode6 = httpConn6.getResponseCode();
		this.annotation_indeces.removeAllElements();                  // clear the existing annotation buffers
		this.annotation_values.removeAllElements();
		
		if(responseCode6 == HttpURLConnection.HTTP_OK)
		    {
			InputStream in6 = httpConn6.getInputStream(); 
			Reader reader6 = new InputStreamReader(in6);
			BufferedReader bufferedReader6 = new BufferedReader(reader6);
			String line6;                                       // annotations streamed in two-line pairs, first line is sample # (int), next line is annotation (string)
		
			
			while((line6 = bufferedReader6.readLine()) != null)
			    {
				if(!line6.equals("none"))
				    {
					String tmpval6 = new String(line6);
					//nextactiveannottime.addElement(tmpval6);
					this.next_time  = Long.parseLong(tmpval6.trim());
					this.START_INDEX = this.next_time;
					
					//this.START_INDEX = 16;
				    }
				else
				    {
					//this.START_INDEX = 16;
					
				    }
				
			    }
			bufferedReader6.close();
		    } 
		httpConn6.disconnect();
		
			
	    }
        catch (MalformedURLException e) {System.out.println("Malformed URL:" + e);}
        catch (IOException e) {System.out.println("IOException:" + e);}
	
	
	int expected_signal_size;
	if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
	    {expected_signal_size = -this.X_SCALE*(this.rightx-this.grid_x_threshold);}
	else
	    {expected_signal_size = (this.rightx-this.grid_x_threshold)/this.X_SCALE;}
	if(this.signal.size() < expected_signal_size) {return;}

	this.init("NO_RESET");      
	this.point = null;
	this.point2 = null;
	this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
	this.CURRENTLY_CLICKED_ANN_INDEX = -1;
	if(this.MOVIE_IS_PLAYING == false) 
	    {
		this.repaint();
	    }
	
    }
    
    //new function implementation to send desired annotation to server script, the server responds with the signal name and time of previous instance
    public void prev_annot()
    {
	int none = 1;
	
	try
	    {
		URL u6;
		if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
		    {u6 = new URL(this.SERVER_URL9 + "&index=" + this.START_INDEX + "&width=" + -this.X_SCALE*(this.rightx-this.grid_x_threshold) + "&CMD=ANN2" + "&ANNTYPE=" + this.anntype + "&WANTED=" + this.active_annotation);}
		else
		    {u6 = new URL(this.SERVER_URL9 + "&index=" + this.START_INDEX + "&width=" + (this.rightx-this.grid_x_threshold)/this.X_SCALE + "&CMD=ANN2" + "&ANNTYPE=" + this.anntype + "&WANTED=" + this.active_annotation);} 
		URLConnection conn6 = u6.openConnection(); 
		HttpURLConnection httpConn6 = (HttpURLConnection) conn6;
		int responseCode6 = httpConn6.getResponseCode();
		this.annotation_indeces.removeAllElements();                  // clear the existing annotation buffers
		this.annotation_values.removeAllElements();
		
		if(responseCode6 == HttpURLConnection.HTTP_OK)
		    {
			InputStream in6 = httpConn6.getInputStream(); 
			Reader reader6 = new InputStreamReader(in6);
			BufferedReader bufferedReader6 = new BufferedReader(reader6);
			String line6;                                       // annotations streamed in two-line pairs, first line is sample # (int), next line is annotation (string)
		
			
			while((line6 = bufferedReader6.readLine()) != null)
			    {
				if(!line6.equals("none"))
				    {
					String tmpval6 = new String(line6);
					this.next_time  = Long.parseLong(tmpval6.trim());
					this.START_INDEX = this.next_time;
			       
				    }
				else
				    {
					//FOR NOW, IF DESIRED ANNOTATION NOT FOUND DO NOTHING
				    }
				
			    }
			bufferedReader6.close();
		    } 
		httpConn6.disconnect();
		
			
	    }
        catch (MalformedURLException e) {System.out.println("Malformed URL:" + e);}
        catch (IOException e) {System.out.println("IOException:" + e);}
	
	
	int expected_signal_size;
	if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
	    {expected_signal_size = -this.X_SCALE*(this.rightx-this.grid_x_threshold);}
	else
	    {expected_signal_size = (this.rightx-this.grid_x_threshold)/this.X_SCALE;}
	if(this.signal.size() < expected_signal_size) {return;}
	

	this.init("NO_RESET");      
	this.point = null;
	this.point2 = null;
	this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
	this.CURRENTLY_CLICKED_ANN_INDEX = -1;
	if(this.MOVIE_IS_PLAYING == false) 
	    {
		this.repaint();
	    }
    }

  public void set_active_annotation(String active_annot)
    {
    this.active_annotation = active_annot;
    }

  public void set_active_signal(String active_signal)
    {
    this.signalname = active_signal;
    }



  protected int ConvertYUnitstoPix(float yval)
    {
    // NOTE: Units to pixels conversion accounts for the fact that Java canvas uses inverse y-axis
    return (int)( (float)this.unitsperpixel_y_den/(float)this.unitsperpixel_y_num * yval );
    }

  protected int ConvertXUnitstoPix(float xval)
    {
    return (int)( (float)this.unitsperpixel_x_den/(float)this.unitsperpixel_x_num * xval );
    }

  protected float ConvertYPixtoUnits(int ypixval)
    {
    // NOTE: Java canvas uses inverse y-axis
    float tmp = (float)this.unitsperpixel_y_num/(float)this.unitsperpixel_y_den*(float)(this.bot-this.grid_y_threshold-ypixval);
    return tmp;
    }

  protected float ConvertXPixtoUnits(int xpixval)
    {
    // NOTE: Java canvas uses inverse y-axis
    float tmp = (float)this.unitsperpixel_x_num/(float)this.unitsperpixel_x_den*(float)(xpixval-this.grid_x_threshold);
    return tmp;
    }

  public void addRadio(ButtonGroup group, String name, String status)
    {

    }

  public void addPopupMenuItem(String menuitem)
    {
    JMenuItem mi=new JMenuItem(menuitem);
    mi.addActionListener(new ActionListener() 
      {
      public void actionPerformed(ActionEvent e)   // note: 'this' keyword does NOT refer to MultiChannel_Movie_Canvas here!
	  {
	  // String command = e.getActionCommand();                                                                                
          }
      });
    popup.add(mi);
    }		   

  public void addRadiotoSubMenu(JMenu submenu, ButtonGroup group, String name, String status)
    {

    }

  protected void ParentUpdate(Object obj1)
    {
    // MultiChannel_Movie_Canvas is not currently supported as a parent of another Canvas
    }

  protected void ParentUpdate(Object obj1, Object obj2)
    {
    // MultiChannel_Movie_Canvas is not currently supported as a parent of another Canvas
    }

  // called from GridCanvas parent
  protected void ChildUpdate(Object index_grandparent_Integer, Object index_parent_Integer)
    {
	//int index_grandparent = ((Integer)index_grandparent_Integer).intValue();
	//int index_parent;

	//this.GRANDPARENT_ACTIVE_10MIN_SEGMENT = index_grandparent;

	//if(this.PARENT_DISPLAY_MODE.equals("ZOOM"))
	//{
      // cast to double to avoid premature truncation
      //index_parent = (int)(((double)((Integer)index_parent_Integer).intValue()/(double)this.PARENT_ZOOM_FACTOR)*((double)this.TOPPANEL_SECS_PER_PIXEL*(double)this.TACH_SAMPLING_FREQUENCY));
      //}
	//else
	//{
	//index_parent = ((Integer)index_parent_Integer).intValue();
	//}

    // calculate a new index based on the grandparent and parent points that are active (ie clicked on)
    //double tmp_secs = (double)index_grandparent*(double)this.TOPPANEL_SECS_PER_PIXEL + (double)index_parent/this.TACH_SAMPLING_FREQUENCY;
    //this.START_INDEX = (long) (tmp_secs*this.SAMPLING_FREQUENCY)-(this.rightx-this.grid_x_threshold)/2;     // shift to put ECG points of interest in center of rendering
    //if(this.START_INDEX < 0) {this.START_INDEX = 0;}
    //this.init("NO_RESET"); 
    //this.point = null;
    //this.point2 = null;
    //this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    //this.CURRENTLY_CLICKED_ANN_INDEX = -1;
    //this.repaint();     
    }

  // called from HistogramCanvas parent - notification of histogram scan request
  protected void ChildUpdate(Object obj1)
    {
	//Integer start_bin_val = (Integer)(((Vector)obj1).elementAt(0)); 
	//Integer end_bin_val = (Integer)(((Vector)obj1).elementAt(1)); 
	//this.SCAN_MODE = (String)(((Vector)obj1).elementAt(2));
	//this.FIRST_BIN=start_bin_val.intValue();
	//this.LAST_BIN=end_bin_val.intValue()-1;
	//if(this.SCAN_MODE.equals("HIST"))
	//{
	//this.CURRENT_BIN = this.FIRST_BIN; 
	//this.next_annot();
	//} 
	//if(this.SCAN_MODE.equals("ANNOT"))
	//{
	//if(this.Transient_Txt != null) {this.removeText(Transient_Txt);}
	//this.Transient_Txt = null;
	//this.caliper_begin = -1;
	//this.caliper_end = -1;
	//this.HISTOGRAM_SCAN_LINENUM = -1;
	//this.HISTOGRAM_SCAN_INDEX = 0;
	//}

	//this.repaint();
    }

 
  
    // paintComponent overrides abstract method for JComponent
    protected void paintComponent(Graphics g1) 
    {
	Graphics2D g = (Graphics2D)g1;
	Insets insets = getInsets();
	this.top = insets.top;
	this.bot = getHeight()-insets.bottom;
	this.leftx = insets.left;
	this.rightx = getWidth()-insets.right;
	
	// initialize canvas signal buffers and other initialization params if this is first draw
	if(this.firstDraw == true && this.unitsperpixel_x_num != -1)
	{
	     this.init();
	     this.firstDraw = false;
	}
	
    // paint the background 
	g.setColor(Color.WHITE);
	g.fillRect(0, 0, getWidth(), getHeight());
	
	this.drawlimits(g);
	g.setColor(Color.lightGray);

	int temp =(int)( (500/this.unitsperpixel_y_num)+.5);
	int increment  = (int)((temp/.5)+.5);
	if(this.Y_SCALE > 0)
	    {
		this.gridy = (int)((500/increment)+.5);
		this.gridy = (int)(((float)(this.gridy) * this.Y_SCALE)+.5);
	    }

	//this.drawGrid(g, this.gridx, this.gridy);  
	this.drawTextLabels(g);
	
	if(this.signal.size() > 0)
	    {
		this.drawTimeStamps(g);
	    }
	
	if(this.DRAW_BLANK_CANVAS == true) 
	    {
		this.DRAW_BLANK_CANVAS = false;
		return;
	    }
	
	// If user has clicked on a point, paint a line on top (unless the movie is playing)
	if(point != null && this.MOVIE_IS_PLAYING == false && this.CURRENTLY_CLICKED_ANN_INDEX != -1) 
	    {
		if(this.X_SCALE >= 1)             // zoomed on x-axis or at default of 1x 
		    {g.fillRect((int)(this.grid_x_threshold-5+(this.CURRENTLY_CLICKED_ANN_INDEX-this.START_INDEX)/this.X_SCALE), 0, 11, this.bot-this.grid_y_threshold);}
		else                              // zoomed out on x-axis
		    {g.fillRect((int)(this.grid_x_threshold-5+(this.CURRENTLY_CLICKED_ANN_INDEX-this.START_INDEX)*-this.X_SCALE), 0, 11, this.bot-this.grid_y_threshold);}    
	    }
	//	this.changegridX(g);

    // Mouse move event
    //if(point2 != null && this.MOVIE_IS_PLAYING == false) 
    //  {
    //  if(point2.x >= this.grid_x_threshold && point2.x <= this.rightx)
    //    {
    //    if(this.setuppery == true || this.setlowery == true)
    //	  {
    //      g.setColor(Color.MAGENTA);
    //      g.drawLine(this.leftx+10,point2.y,this.rightx-10,point2.y);
    //      }
    //    if(this.setuppery == false && this.setlowery == false)
    //      {
	      //g.setColor(Color.GREEN);

 
 	  // if there is a pre-existing clicked annotation selected, highlight it
	  //if(this.CURRENTLY_CLICKED_ANN_INDEX != -1)
	  //  {
          //  if(this.X_SCALE >= 1)             // zoomed on x-axis or at default of 1x 
          //    {g.fillRect((int)(this.grid_x_threshold-5+(this.CURRENTLY_CLICKED_ANN_INDEX-this.START_INDEX)*this.X_SCALE), 0, 11, this.bot-this.grid_y_threshold);}
          //  else                              // zoomed out on x-axis
          //    {g.fillRect((int)(this.grid_x_threshold-5+(this.CURRENTLY_CLICKED_ANN_INDEX-this.START_INDEX)/-this.X_SCALE), 0, 11, this.bot-this.grid_y_threshold);}    
    //    }

    //    if(this.CURRENTLY_HIGHLIGHTED_ANN_INDEX != -1)
    //    {
    //        if(this.X_SCALE >= 1)             // zoomed on x-axis or at default of 1x 
    //          {g.fillRect((int)(this.grid_x_threshold-5+(this.CURRENTLY_HIGHLIGHTED_ANN_INDEX-this.START_INDEX)*this.X_SCALE), 0, 11, this.bot-this.grid_y_threshold);}
    //       else                              // zoomed out on x-axis
    //          {g.fillRect((int)(this.grid_x_threshold-5+(this.CURRENTLY_HIGHLIGHTED_ANN_INDEX-this.START_INDEX)/-this.X_SCALE), 0, 11, this.bot-this.grid_y_threshold);}    
    //    }
    //
    //    g.drawLine(point2.x,this.top,point2.x,this.bot-grid_y_threshold);
    //  }
    //}
    //}

    //if (point3 != null && point4 != null && this.MOVIE_IS_PLAYING == false)
    //  {
    //  g.setColor(Color.CYAN);
    //  g.fillRect(point3.x, this.bot/2-10, (point4.x-point3.x), 20);
    //  }

    // draw caliper, RR-interval and HR if we're in HIST mode
    //if(this.SCAN_MODE.equals("HIST"))
    //  {
    //  g.setColor(Color.RED);
    //  g.setStroke(new BasicStroke(5));
    //  if(this.X_SCALE >= 1)
    //	{
    //    g.drawLine((int)(this.grid_x_threshold+(this.caliper_begin-this.START_INDEX)*this.X_SCALE),this.bot/2,(int)(this.grid_x_threshold+(this.caliper_end-this.START_INDEX)*this.X_SCALE),this.bot/2);}
    //  else
    //    {g.drawLine((int)(this.grid_x_threshold+(this.caliper_begin-this.START_INDEX)/-this.X_SCALE),this.bot/2,(int)(this.grid_x_threshold+(this.caliper_end-this.START_INDEX)/-this.X_SCALE),this.bot/2);}
    //  g.setStroke(new BasicStroke(0));

    //  }

    //ALI UNCOMMENTED THIS
	this.drawAnnotations(g);
	this.drawSignal(g);
	
    }   // end paint component method
    

  protected void slider_slid(int value)
    {
    this.MOVIE_SPEED_SCALE = value;
    }



 protected void slider_movie(int value)
    {
	int endtime = (int)this.END_INDEX;
	float numer = (float) value;
	float denom = (float)100;
	float offset = numer/denom;
	int jumptime = (int)((offset*this.END_INDEX)+.5);	   
	if(this.ANNOT_ADVANCE == 0)
	    this.START_INDEX = jumptime;
	else{
	    this.START_INDEX = this.TEMP_START_INDEX;
	    this.ANNOT_ADVANCE = 0;
	    this.TEMP_START_INDEX = 0;
	}
	this.init("NO_RESET");      
	this.point = null;
	this.point2 = null;
	this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
	this.CURRENTLY_CLICKED_ANN_INDEX = -1;
	if(this.MOVIE_IS_PLAYING == false) 
	    {
		this.repaint();
	    }
	
    }

    //this is now the ZOOM-X slider
 protected void slider_slid1(int value)
    {

	if(value == 0)
	    {
		X_SCALE = -10;
		zoom_in_x_click();
	    }
	else if(value == 10)
	    {
		X_SCALE = -8;
		zoom_in_x_click();
	    }
	else if(value == 20)
	    {
		X_SCALE = -7;
		zoom_in_x_click();
	    }
	else if(value == 30)
	    {
		X_SCALE = -6;
		zoom_in_x_click();
	    }
	else if(value == 40)
	    {
		X_SCALE = -5;
		zoom_in_x_click();
	    }
	else if(value == 50)
	    {
		X_SCALE = -4;
		zoom_in_x_click();
	    }
	else if(value == 60)
	    {
		X_SCALE = -2;
		zoom_in_x_click();
	    }
	else if(value == 70)
	    {
		X_SCALE = 1;
		zoom_in_x_click();
	    }
	else if(value == 80)
	    {
		X_SCALE = 3;
		zoom_in_x_click();
	    }
	else if(value == 90)
	    {
		X_SCALE = 5;
		zoom_in_x_click();
	    }
	else if(value == 100)
	    {
		X_SCALE = 7;
		zoom_in_x_click();
	    }

    }
    //this isnow for the ZOOM-Y slider
 protected void slider_slid2(int value)
    {
	

	if(value == 0)
	    {
		this.Y_SCALE = (float)(.05);
		zoom_in_y_click();
	    }
	else if(value == 20)
	    {
		this.Y_SCALE = (float)(.15);
		zoom_in_y_click();
	    }
	else if(value == 40)
	    {
		this.Y_SCALE = (float)(.25);
		zoom_in_y_click();
	    }
	else if(value == 60)
	    {
		this.Y_SCALE = (float)(.35);
		zoom_in_y_click();
	    }
	else if(value == 80)
	    {
		this.Y_SCALE = (float)(.45);
		zoom_in_y_click();
	    }
	else if(value == 100)
	    {
		this.Y_SCALE = (float)(.6);
		zoom_in_y_click();
	    }

    }


  protected void zoom_in_x_click()
    {
	//if(this.X_SCALE >= 1 || this.X_SCALE < -2) {this.X_SCALE++;}
	//if(this.X_SCALE == -2) {this.X_SCALE = 1;}
    this.init("NO_RESET");
    this.point = null;
    this.point2 = null;
    this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    this.CURRENTLY_CLICKED_ANN_INDEX = -1;
    this.repaint();
   
    }

  protected void zoom_out_x_click()
    {
	// if(this.X_SCALE > 1 || this.X_SCALE <= -2) {this.X_SCALE--;}
	//    if(this.X_SCALE == 1) {this.X_SCALE = -2;}                  
    this.init("NO_RESET");
    this.point = null;
    this.point2 = null;
    this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    this.CURRENTLY_CLICKED_ANN_INDEX = -1;
    this.repaint();
   
    }
    //these functions are not currently utilized
  protected void zoom_in_y_click()
    {
	// this.Y_SCALE += 0.1;    
    this.repaint();
    }
    //these functions are not currently utilized
  protected void zoom_out_y_click()
    {
	// if(Y_SCALE > 0) {this.Y_SCALE -= 0.1;}         
    this.repaint();
  
    }

    //shows the signal and adds a "1" in the sigvals corresponding index
 protected void addsignal_button_click()
    {
	String holder;
	String value = "1";
	for(int j =0; j <sigs.getSize(); j++){
	    holder = (String)this.sigs.getElementAt(j);
	    if(signalname.equals(holder)){
		sigvals.add(j,value);
		sigvals.remove(j+1);
	    }
	}	
	this.repaint();
       
    }
    //this function is called if the "show all" checkbox is clicked
    protected void show_all_sigs()
    {
	String value = "1";
	for(int j =0; j <sigs.getSize(); j++){
	    sigvals.add(j,value);
	    sigvals.remove(j+1);
	}

	JCheckBoxMenuItem cbMenuItem;
	CheckBoxListener cblistener;	    
	submenu.removeAll();
	String holder;
	for(int z=0; z<sigs.getSize();z++)
	    {
		holder = (String)sigs.getElementAt(z);		       
		cbMenuItem = new JCheckBoxMenuItem(holder);
		cblistener = new CheckBoxListener();
		cbMenuItem.addItemListener(cblistener);
		cbMenuItem.setState(true);
		submenu.add(cbMenuItem);
	    }
	cbMenuItem = new JCheckBoxMenuItem("Show All");
	cblistener = new CheckBoxListener();
	cbMenuItem.addItemListener(cblistener);
	cbMenuItem.setState(false);
	submenu.add(cbMenuItem);
	
	popup.revalidate();
	popup.repaint();
    }
//hides the signal and adds a "0" in the sigvals corresponding index
protected void removesignal_button_click()
    {
	String holder;
	String value = "0";
	for(int j =0; j <sigs.getSize(); j++){
	    holder = (String)this.sigs.getElementAt(j);
	    if(signalname.equals(holder)){
		sigvals.add(j,value);
		sigvals.remove(j+1);
	    }
	}

	this.repaint();
       
    }
    //This class and its methods  implement the checkbox listener action callbacks()
 class CheckBoxListener implements ItemListener {
     public void itemStateChanged(ItemEvent e) {
	 if (e.getStateChange()==ItemEvent.DESELECTED){
	     
	     JCheckBoxMenuItem source = (JCheckBoxMenuItem)e.getItemSelectable();
	     String temp = (String)source.getLabel();
	     set_active_signal(temp);
	     removesignal_button_click();
	 }
	 else if (e.getStateChange()==ItemEvent.SELECTED){
	     
	     JCheckBoxMenuItem source = (JCheckBoxMenuItem)e.getItemSelectable();
	     String temp = (String)source.getLabel();
	     if(temp.equals("Show All"))
		show_all_sigs();
	     else
		 {
		     set_active_signal(temp);
		     addsignal_button_click();
		 }
	 }		
	 
     }
 }



  protected void prev_button_click()
    {
    // is this a reversal of direction?
    if(this.DIRECTION.equals("F")) {this.renderedannotations.removeAllElements();}
    this.DIRECTION = "B";

    if(this.START_INDEX != 0)           // 0th index is beginning of all data
      {
      if(this.X_SCALE >= 1)             // zoomed on x-axis or at default of 1x 
	  {this.START_INDEX -= (this.rightx-(this.grid_x_threshold))/X_SCALE;}
      else                              // zoomed out on x-axis
	  {this.START_INDEX -= (this.rightx-(this.grid_x_threshold))*-this.X_SCALE;}                                        
      if(this.START_INDEX < 0) 
        {this.START_INDEX = 0;}        // don't allow START_INDEX to be less than 0
      
      this.init("NO_RESET");     
      this.point = null;
      this.point2 = null;
      this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
      this.CURRENTLY_CLICKED_ANN_INDEX = -1; 
      this.repaint();

      // update parents & grandparents on movement
      //int grandparent_pixels = (int)( ((double)this.START_INDEX/this.SAMPLING_FREQUENCY)/(float)this.TOPPANEL_SECS_PER_PIXEL );
      //int parent_pixels = (int)(((double)this.START_INDEX/this.SAMPLING_FREQUENCY - grandparent_pixels*this.TOPPANEL_SECS_PER_PIXEL)* this.TACH_SAMPLING_FREQUENCY);
      //Enumeration enum_par = this.parents.elements();
      //while(enum_par.hasMoreElements()) 
      //  {
      //  CustomCanvas currentparent = (CustomCanvas) enum_par.nextElement();
      //  currentparent.ParentUpdate(new Integer(grandparent_pixels), new Integer(parent_pixels));
      //  }
      }
    else {}                             // already at beginning - do nothing
    }

  protected void prev_button_half_click()
    {
    // is this a reversal of direction?
    if(this.DIRECTION.equals("F")) {this.renderedannotations.removeAllElements();}
    this.DIRECTION = "B";

    if(this.START_INDEX != 0)           // 0th index is beginning of all data
       {
       if(this.X_SCALE >= 1)             // zoomed on x-axis or at default of 1x 
	  {
	      this.START_INDEX -= (this.rightx-(this.grid_x_threshold))/(2*X_SCALE);
          }
       else                              // zoomed out on x-axis
          {
	      this.START_INDEX -= (this.rightx-(this.grid_x_threshold))*-this.X_SCALE/2;
          }                                        
       if(this.START_INDEX < 0) {this.START_INDEX = 0;}        // don't allow START_INDEX to be less than 0
       
       this.init("NO_RESET");      
       this.point = null;
       this.point2 = null;
       this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
       this.CURRENTLY_CLICKED_ANN_INDEX = -1;
       this.repaint();

       // update parents on movement
       //int grandparent_pixels = (int)( ((double)this.START_INDEX/this.SAMPLING_FREQUENCY)/(float)this.TOPPANEL_SECS_PER_PIXEL );
       //int parent_pixels = (int)(((double)this.START_INDEX/this.SAMPLING_FREQUENCY - grandparent_pixels*this.TOPPANEL_SECS_PER_PIXEL)* this.TACH_SAMPLING_FREQUENCY);
       //Enumeration enum_par = this.parents.elements();
       //while(enum_par.hasMoreElements()) 
       //  {
       //  CustomCanvas currentparent = (CustomCanvas) enum_par.nextElement();
       //  currentparent.ParentUpdate(new Integer(grandparent_pixels), new Integer(parent_pixels));
       //  }
       }

    else{}   // already at beginning - do nothing
   }


  protected void next_button_click()
    {
    // is this a reversal of direction?
    if(this.DIRECTION.equals("B")) {this.renderedannotations.removeAllElements();}
    this.DIRECTION = "F";

    int expected_signal_size;
    if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
	{expected_signal_size = -this.X_SCALE*(this.rightx-(this.grid_x_threshold));}
    else
	{expected_signal_size = (this.rightx-(this.grid_x_threshold))/this.X_SCALE;}
    if(this.signal.size() < expected_signal_size) {return;}

    if(this.X_SCALE >= 1)               
	{this.START_INDEX += (this.rightx-(this.grid_x_threshold))/X_SCALE;}
    else
	{this.START_INDEX += (this.rightx-(this.grid_x_threshold))*-this.X_SCALE;}

    this.init("NO_RESET");      
    this.point = null;
    this.point2 = null;
    this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    this.CURRENTLY_CLICKED_ANN_INDEX = -1;
    if(this.MOVIE_IS_PLAYING == false) 
       {
       this.repaint();
       }

    // update parents on movement
    //int grandparent_pixels = (int)( ((double)this.START_INDEX/this.SAMPLING_FREQUENCY)/(float)this.TOPPANEL_SECS_PER_PIXEL );
    //int parent_pixels = (int)(((double)this.START_INDEX/this.SAMPLING_FREQUENCY - grandparent_pixels*this.TOPPANEL_SECS_PER_PIXEL)* this.TACH_SAMPLING_FREQUENCY);
    //Enumeration enum_par = this.parents.elements();
    //while(enum_par.hasMoreElements()) 
    //  {
    //  CustomCanvas currentparent = (CustomCanvas) enum_par.nextElement();
    //  currentparent.ParentUpdate(new Integer(grandparent_pixels), new Integer(parent_pixels));
    //  }
    }



  protected void next_button_half_click()
    {
    // is this a reversal of direction?
    if(this.DIRECTION.equals("B")) {this.renderedannotations.removeAllElements();}
    this.DIRECTION = "F";

    int expected_signal_size;
    if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
	{expected_signal_size = -this.X_SCALE*(this.rightx-(this.grid_x_threshold));}
    else
	{expected_signal_size = (this.rightx-(this.grid_x_threshold))/this.X_SCALE;}
    if(this.signal.size() < expected_signal_size) {return;}

    if(this.X_SCALE >= 1)               
	{this.START_INDEX += (this.rightx-(this.grid_x_threshold))/(2*X_SCALE);}
    else
	{this.START_INDEX += -this.X_SCALE*(this.rightx-(this.grid_x_threshold))/2;}

    this.init("NO_RESET");
    this.point = null;
    this.point2 = null;
    this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    this.CURRENTLY_CLICKED_ANN_INDEX = -1;      
    this.repaint();

    // update parents on movement
    //int grandparent_pixels = (int)( ((double)this.START_INDEX/this.SAMPLING_FREQUENCY)/(float)this.TOPPANEL_SECS_PER_PIXEL );
    //int parent_pixels = (int)(((double)this.START_INDEX/this.SAMPLING_FREQUENCY - grandparent_pixels*this.TOPPANEL_SECS_PER_PIXEL)* this.TACH_SAMPLING_FREQUENCY);
    //Enumeration enum_par = this.parents.elements();
    //while(enum_par.hasMoreElements()) 
    //  {
    //  CustomCanvas currentparent = (CustomCanvas) enum_par.nextElement();
    //  currentparent.ParentUpdate(new Integer(grandparent_pixels), new Integer(parent_pixels));
    //  }
    }

  public void reset()
    {
    this.SERVER_URL2 = null;           // initialized in constructor
    this.SERVER_URL3 = null;           // initialized in constructor
    this.SERVER_URL4 = null;           // initialized in constructor
    this.TACH_SAMPLING_FREQUENCY=-1;    // initialized in init()
    this.NUM_CHANNELS = 0;                // initialized in init()
    this.SAMPLING_FREQUENCY=-1;         // initialized in init()
    this.TOPPANEL_SECS_PER_PIXEL=-1;    // initialized in init()
    this.MOVIE_PIXEL_OFFSET = 0;          // if movie is running, only increments of signal are drawn in repaint method
    this.MOVIE_SPEED_SCALE = 5;          // changed when rendering speed (playback speed slider) is adjusted
    this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    this.CURRENTLY_CLICKED_ANN_INDEX = -1;
    this.MOVIE_IS_PLAYING = false; 
    this.DRAW_BLANK_CANVAS = false;
    this.ADDING_NEW_ANNOTATION = false;
    this.DELETING_ANNOTATION = false;
    this.FIRST_BIN=0;
    this.LAST_BIN=0;
    this.CURRENT_SCAN_INDEX1=0;
    this.CURRENT_SCAN_INDEX2=0;
    this.CURRENT_BIN=-1;
    this.SCAN_MODE = "ANNOT";            // may be "ANNOT" or "HIST"  
    this.FIFO_DEPTH = 50;                   // N-deep FIFO should match MAX_DEPTH in ScopeCanvas.java
    this.DIRECTION = "F";                // may be "F" for forward or "B" for backward
    this.GRANDPARENT_ACTIVE_10MIN_SEGMENT = 0;
    this.caliper_begin = -1;
    this.caliper_end = -1;
    this.HISTOGRAM_SCAN_LINENUM = -1;
    this.HISTOGRAM_SCAN_INDEX = 0; 
    this.TEMP_START_INDEX = 0;
    this.START_INDEX = 0;
    this.END_INDEX = 0;
    this.nsamp = 0;
    this.X_SCALE = -4;
    this.Y_SCALE = (float)0.15;
    this.active_channel_numbers.removeAllElements();
    this.annotation_indeces.removeAllElements();
    this.annotation_values.removeAllElements();
    this.renderedannotations.removeAllElements();
    this.sigvals.clear();
    this.sigs.removeAllElements();
    this.firstDraw = true;
    }

  public void add_movie_button(JButton button_to_add)
    {
    this.movie_buttons.addElement(button_to_add);
    }

  public void add_browser_button(JButton button_to_add)
    {
    this.browser_buttons.addElement(button_to_add);
    }


  protected void movie_pause_button_click()
    {
	// perform partial repaint of canvas
	//timer_interrupt_generator.stop();
	//this.repaint(); 

	timer_interrupt_generator.stop();
	this.MOVIE_IS_PLAYING = false;
	this.MOVIE_PIXEL_OFFSET = 0;
	
	this.point = null;
	this.point2 = null;
	this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
	this.CURRENTLY_CLICKED_ANN_INDEX = -1;
	
	this.renderedannotations.removeAllElements();
	
	Enumeration enum_browser_buttons = this.browser_buttons.elements();
	while(enum_browser_buttons.hasMoreElements()) 
	    {
		JButton currentbutton = (JButton) enum_browser_buttons.nextElement();
		currentbutton.setEnabled(true);
	    }
	
	
	this.repaint(); 
    }


  protected void movie_play_button_click()
    {  
    this.point = null;
    this.point2 = null;
    this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    this.CURRENTLY_CLICKED_ANN_INDEX = -1;

    Enumeration enum_browser_buttons = this.browser_buttons.elements();
    while(enum_browser_buttons.hasMoreElements()) 
      {
      JButton currentbutton = (JButton) enum_browser_buttons.nextElement();
      currentbutton.setEnabled(false);
      }

    // was the movie paused?
    if(this.MOVIE_IS_PLAYING == true) 
      {
      }
    else
      {
      this.draw_blank_canvas();
      this.MOVIE_IS_PLAYING = true;
      }
    timer_interrupt_generator.start();
    }

    //this stop button is now a reset button which initializes the sliders and sets time to zero
  protected void movie_stop_button_click()
    { 
	timer_interrupt_generator.stop();
	this.MOVIE_IS_PLAYING = false;
	this.MOVIE_PIXEL_OFFSET = 0;
	
	this.point = null;
	this.point2 = null;
	this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
	this.CURRENTLY_CLICKED_ANN_INDEX = -1;
	
	this.renderedannotations.removeAllElements();
	
	Enumeration enum_browser_buttons = this.browser_buttons.elements();
	while(enum_browser_buttons.hasMoreElements()) 
	    {
		JButton currentbutton = (JButton) enum_browser_buttons.nextElement();
		currentbutton.setEnabled(true);
	    }
		
	this.START_INDEX = 0;
	this.init("NO_RESET");      
	this.point = null;
	this.point2 = null;
	this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
	this.CURRENTLY_CLICKED_ANN_INDEX = -1;
	this.repaint();
    }


    //not currently utilized
  protected void movie_rewind_button_click()
    {
	movie_stop_button_click();
	while(this.START_INDEX > 0)
	    {
		prev_button_click();
	    }
    }


  protected void draw_blank_canvas()
    {
    this.DRAW_BLANK_CANVAS = true;
    this.repaint();           // set this.DRAW_BLANK_CANVAS = false within repaint - for some reason doing after this.repaint() fails!
    }


  protected void add_annotation_to_server(long time, String active_annotation)
    {
	//if(this.SERVER_URL3 == null) {return;}

	//    try 
	//{
    // get signal information from server
    //URL u = new URL(this.SERVER_URL3 + "&CMD=ADD&TIME=" + time + "&ANN=" + active_annotation + "&TEN_MIN_INDEX=" +  this.GRANDPARENT_ACTIVE_10MIN_SEGMENT); 
    //URLConnection conn = u.openConnection(); 
    //HttpURLConnection httpConn = (HttpURLConnection) conn;
    //int responseCode = httpConn.getResponseCode(); 
    //if(responseCode == HttpURLConnection.HTTP_OK) {}
    //httpConn.disconnect();
    //} 
    //catch (MalformedURLException e) {System.out.println("Malformed URL:" + e);}
    //catch (IOException e) {System.out.println("IOException:" + e);}


    // force the histogram panel to be re-loaded with updated info

    // force the middle (parent) and top-level (grandparent) panels to re-load with updated info [CGI script has re-computed time series to correct for annotation mod]
    }


  protected void delete_annotation_from_server(long time)
    {
	//if(this.SERVER_URL3 == null) {return;}

	//String annot_val = (String)this.annotation_values.elementAt(this.annotation_indeces.indexOf(new Long(time))); 

	//try 
	//{
    // get signal information from server
    //URL u = new URL(this.SERVER_URL3 + "&CMD=DEL&TIME=" + time + "&ANN=" + annot_val + "&TEN_MIN_INDEX=" + this.GRANDPARENT_ACTIVE_10MIN_SEGMENT); 
    //URLConnection conn = u.openConnection(); 
    //HttpURLConnection httpConn = (HttpURLConnection) conn;
    //int responseCode = httpConn.getResponseCode(); 
    //if(responseCode == HttpURLConnection.HTTP_OK) {}
    //httpConn.disconnect();
    //} 
    //catch (MalformedURLException e) {System.out.println("Malformed URL:" + e);}
    //catch (IOException e) {System.out.println("IOException:" + e);}

    // force the histogram panel - if exists - to be re-loaded with updated info

    // force the middle (parent) and top-level (grandparent) panels to re-load with updated info [CGI script has re-computed time series to correct for annotation mod]
    }


  public void timer_interrupt()   // sliding repaint window to avoid excess re-rendering
    {
    int expected_signal_size;
    if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
      {
	  expected_signal_size = -this.X_SCALE*(this.rightx-(this.grid_x_threshold));
      }
    else
      {
	  expected_signal_size = (this.rightx-(this.grid_x_threshold))/this.X_SCALE;
      }

    if(this.signal.size() < expected_signal_size) 
      {
      // turn the movie off and return
      this.movie_stop_button_click();
      return;
      }

    // move to next frame if full canvas has been drawn    
    if(this.MOVIE_PIXEL_OFFSET > (this.rightx-(this.grid_x_threshold))+this.MOVIE_SPEED_SCALE)
      {
      this.draw_blank_canvas();
      this.MOVIE_PIXEL_OFFSET = -this.MOVIE_SPEED_SCALE;     // for some strange reason setting to 0 doesn't work - need to start further to left!
      this.next_button_click();
      }

    // perform partial repaint of canvas
    this.repaint((this.grid_x_threshold)+this.MOVIE_PIXEL_OFFSET,0,this.MOVIE_SPEED_SCALE,this.bot-this.grid_y_threshold);

    // increment to the next segment of the canvas that is to be drawn
    this.MOVIE_PIXEL_OFFSET += this.MOVIE_SPEED_SCALE;
    }


  // called on first canvas paint invokation
  protected void init()
    {
	int x_last;
	popup_on_off = 0;
	// initialize slider
	this.slider_slid(this.MOVIE_SPEED_SCALE);
	
	if(this.SERVER_URL == null || this.SERVER_URL2 == null) {return;}
	
	// start the timer - if a previous timer exists, stop it and free mem
	if(this.timer_interrupt_generator != null)
	    {this.timer_interrupt_generator.stop(); this.timer_interrupt_generator = null;}
	this.timer_interrupt_generator = new TimerInterruptGenerator(this);
	
	try 
	    {
		// get signal information from server
		URL u = new URL(this.SERVER_URL + "&INFOTYPE=NUMCHANNELS"); 
		URLConnection conn = u.openConnection(); 
		HttpURLConnection httpConn = (HttpURLConnection) conn;
		int responseCode = httpConn.getResponseCode(); 
		if(responseCode == HttpURLConnection.HTTP_OK)
		    {
			InputStream in = httpConn.getInputStream(); 
			Reader reader = new InputStreamReader(in);
			BufferedReader bufferedReader = new BufferedReader(reader);
			String line;
			while((line = bufferedReader.readLine()) != null)
			    {
				Integer tmpval = new Integer(line);
				this.NUM_CHANNELS = (int)(tmpval.longValue());
			    }
			bufferedReader.close();
		    }
		httpConn.disconnect();
		
		// by default set all channels active
		for(int i=1; i<=this.NUM_CHANNELS; i++) {active_channel_numbers.addElement(new Integer(i));}
		
		URL u2;
		if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
		    {
			String URL_String = new String(this.SERVER_URL2 + "&index=" + this.START_INDEX + "&width=" + -this.X_SCALE*(this.rightx-(this.grid_x_threshold)) + "&CMD=SIG");
			u2 = new URL(URL_String);
		    }
		else
		    {
			String URL_String = new String(this.SERVER_URL2 + "&index=" + this.START_INDEX + "&width=" + (this.rightx-(this.grid_x_threshold))/this.X_SCALE + "&CMD=SIG");
			u2 = new URL(URL_String);
		    } 
		URLConnection conn2 = u2.openConnection(); 
		HttpURLConnection httpConn2 = (HttpURLConnection) conn2;
		int responseCode2 = httpConn2.getResponseCode();
		this.signal.removeAllElements();                  // clear the existing signal buffer
		if(responseCode2 == HttpURLConnection.HTTP_OK)
		    {
			InputStream in2 = httpConn2.getInputStream(); 
			Reader reader2 = new InputStreamReader(in2);
			BufferedReader bufferedReader2 = new BufferedReader(reader2);
			String line2, holder;
			int i = 0;
			int found =0;
			this.signalnames.clear();
			//sigvals.clear();
			//sigs.removeAllElements();
			while((line2 = bufferedReader2.readLine()) != null)
			    {
				if(i%2 == 0){
				    Double tmpval2 = new Double(line2);
				    signal.addElement(tmpval2);
				}
				else{
				    signalnames.addElement(line2);
				    
				    for(int j =0; j < sigs.getSize(); j++){
					holder = (String)sigs.getElementAt(j);
					if(line2.equals(holder)){
					    found = 1;
					    break;
					}
				    }
				    if(found == 0){
					sigs.addElement(line2);
					sigvals.addElement("1");			       
				    }
				    
				    
				}
				i++;
			    }
			bufferedReader2.close();
		    }
		httpConn2.disconnect();
		
		//THIS IS ALI UMCOMMENTING CODE BELOW//////////////////////////////////
		URL u6;
		if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
		    {u6 = new URL(this.SERVER_URL2 + "&index=" + this.START_INDEX + "&width=" + -this.X_SCALE*(this.rightx-(this.grid_x_threshold)) + "&CMD=ANN" + "&ANNTYPE=" + this.anntype);}
		else
		    {u6 = new URL(this.SERVER_URL2 + "&index=" + this.START_INDEX + "&width=" + (this.rightx-(this.grid_x_threshold))/this.X_SCALE + "&CMD=ANN" + "&ANNTYPE=" + this.anntype);} 
		URLConnection conn6 = u6.openConnection(); 
		HttpURLConnection httpConn6 = (HttpURLConnection) conn6;
		int responseCode6 = httpConn6.getResponseCode();
		this.annotation_indeces.removeAllElements();                  // clear the existing annotation buffers
		this.annotation_values.removeAllElements();
		if(responseCode6 == HttpURLConnection.HTTP_OK)
		    {
			InputStream in6 = httpConn6.getInputStream(); 
			Reader reader6 = new InputStreamReader(in6);
			BufferedReader bufferedReader6 = new BufferedReader(reader6);
			String line6;                                       // annotations streamed in two-line pairs, first line is sample # (int), next line is annotation (string)
			int i = 0;
			
			while((line6 = bufferedReader6.readLine()) != null)
			    {
				if(!line6.equals(""))
				    {
					if(i%2 == 0) 
					    {
						Long tmpval6 = new Long(line6);
						annotation_indeces.addElement(tmpval6);
					    }
					else 
					    {
						String tmpval6 = new String(line6);
						annotation_values.addElement(tmpval6);
					    }
					i++;
				    }
			    }
			bufferedReader6.close();
		    } 
		httpConn6.disconnect();
		//////////////////////WAS COMMENTED ABOVE/////////////////////////////////////////////////
		
		
		//URL u3 = new URL(this.SERVER_URL + "&INFOTYPE=TACHSAMPFREQ"); 
		//URLConnection conn3 = u3.openConnection(); 
		//HttpURLConnection httpConn3 = (HttpURLConnection) conn3;
		//int responseCode3 = httpConn3.getResponseCode(); 
		//if(responseCode3 == HttpURLConnection.HTTP_OK)
		//  {
		//  InputStream in = httpConn3.getInputStream(); 
		//  Reader reader = new InputStreamReader(in);
		//  BufferedReader bufferedReader = new BufferedReader(reader);
		//  String line;
		//  while((line = bufferedReader.readLine()) != null)
		//    {
		//    Float tmpval = new Float(line);
		//    this.TACH_SAMPLING_FREQUENCY = tmpval.floatValue();
		//    }
		//  bufferedReader.close();
		//  }
		//httpConn3.disconnect();
		
		URL u4 = new URL(this.SERVER_URL + "&INFOTYPE=SAMPFREQ"); 
		URLConnection conn4 = u4.openConnection(); 
		HttpURLConnection httpConn4 = (HttpURLConnection) conn4;
		int responseCode4 = httpConn4.getResponseCode(); 
		if(responseCode4 == HttpURLConnection.HTTP_OK)
		    {
			InputStream in = httpConn4.getInputStream(); 
			Reader reader = new InputStreamReader(in);
			BufferedReader bufferedReader = new BufferedReader(reader);
			String line;
			while((line = bufferedReader.readLine()) != null)
			    {
				Float tmpval = new Float(line);
				this.SAMPLING_FREQUENCY = tmpval.floatValue();
			    }
			bufferedReader.close();
		    }
		httpConn4.disconnect();
		
		//URL u5 = new URL(this.SERVER_URL + "&INFOTYPE=TOPPANEL_SECS_PER_PIXEL"); 
		//URLConnection conn5 = u5.openConnection(); 
		//HttpURLConnection httpConn5 = (HttpURLConnection) conn5;
		//int responseCode5 = httpConn5.getResponseCode(); 
		//if(responseCode5 == HttpURLConnection.HTTP_OK)
		//  {
		//  InputStream in = httpConn5.getInputStream(); 
		//  Reader reader = new InputStreamReader(in);
		//  BufferedReader bufferedReader = new BufferedReader(reader);
		//  String line;
		//  while((line = bufferedReader.readLine()) != null)
		//    {
		//    Float tmpval = new Float(line);
		//    this.TOPPANEL_SECS_PER_PIXEL = tmpval.floatValue();
		//    }
		//  bufferedReader.close();
		//  }
		//httpConn5.disconnect();
		
	    }
	catch (MalformedURLException e) {System.out.println("Malformed URL:" + e);}
	catch (IOException e) {System.out.println("IOException:" + e);}
	
	// set interrupt generator to go off at 5x sampling rate (note conversion to ms from Hz) - generator not started here, just initialized
	this.timer_interrupt_generator.setDelay(5*(int)(1000/this.SAMPLING_FREQUENCY));
	
	// tell children (ScopeCanvas) how many channels are available and send the signal & annotation vectors
	//Enumeration enum_child = this.children.elements();
	//while(enum_child.hasMoreElements()) 
	//  {
	//  CustomCanvas currentchild = (CustomCanvas) enum_child.nextElement();
	//  currentchild.ChildUpdate(new Integer(-this.NUM_CHANNELS));     // note: Scope Canvas expects a negative num to avoid confusion in Histogram_Canvas with ints sent from GridCanvas to children
	//  Vector multidimensional_vector = new Vector();
	//  multidimensional_vector.addElement(this.signal);
	//  multidimensional_vector.addElement(this.annotation_indeces);
	//  multidimensional_vector.addElement(this.annotation_values);
	//  multidimensional_vector.addElement(new Long(this.START_INDEX));
	//  currentchild.ChildUpdate(multidimensional_vector);
	//  }
	set_end();
    }




  // polymorphic init called on subsequent invocations - no need to re-create popup menu or determine number of signals
  protected void init(String Directive)        // directive may be "NO_RESET"
    {
	popup_on_off = 0;
	// reset the rendered annotations vector
	//this.renderedannotations.removeAllElements();
	
	if(this.SERVER_URL2 == null) 
	    {return;}
	
	try 
	    {
		// fill signal vector
		URL u2;
		if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
		    {
			String URL_String = new String(this.SERVER_URL2 + "&index=" + this.START_INDEX + "&width=" + -this.X_SCALE*(this.rightx-(this.grid_x_threshold)) + "&CMD=SIG");
			u2 = new URL(URL_String);
		    }
		else
		    {
			String URL_String = new String(this.SERVER_URL2 + "&index=" + this.START_INDEX + "&width=" + (this.rightx-(this.grid_x_threshold))/this.X_SCALE + "&CMD=SIG");
			u2 = new URL(URL_String);
		    }
		URLConnection conn2 = u2.openConnection(); 
		HttpURLConnection httpConn2 = (HttpURLConnection) conn2;
		int responseCode2 = httpConn2.getResponseCode(); 
		this.signal.removeAllElements();                  // clear the existing buffer
		if(responseCode2 == HttpURLConnection.HTTP_OK)
		    {
			InputStream in2 = httpConn2.getInputStream(); 
			Reader reader2 = new InputStreamReader(in2);
			BufferedReader bufferedReader2 = new BufferedReader(reader2);
			String line2, holder;
			int i = 0;
			int found = 0;
			this.signalnames.clear();
			//sigvals.clear();
			//sigs.removeAllElements();
			while((line2 = bufferedReader2.readLine()) != null)
			    {
				if(i%2 == 0){
				    Double tmpval2 = new Double(line2);
				    signal.addElement(tmpval2);
				}
				else{
				    signalnames.addElement(line2);
				    
				    for(int j =0; j <sigs.getSize(); j++){
					holder = (String)this.sigs.getElementAt(j);
					if(line2.equals(holder)){
					    found = 1;
					    break;
					}
				    }
				    if(found == 0){
					sigs.addElement(line2);
					sigvals.addElement("1");				
				    }
				}
				i++;
			    }
			bufferedReader2.close();
		    }
		httpConn2.disconnect();
		
		
		//ALI UNCOMMENTED BELOW/////////////////////////////////////////////////////////
		
		// fill annotation vectors
		
		URL u6;
		if(this.X_SCALE < 0)        // x-axis expanded get multiple frames
		    {u6 = new URL(this.SERVER_URL2 + "&index=" + this.START_INDEX + "&width=" + -X_SCALE*(this.rightx-(this.grid_x_threshold)) + "&CMD=ANN" + "&ANNTYPE=" + this.anntype);}
		else
		    {u6 = new URL(this.SERVER_URL2 + "&index=" + this.START_INDEX + "&width=" + (this.rightx-(this.grid_x_threshold))/X_SCALE + "&CMD=ANN" + "&ANNTYPE=" + this.anntype);} 
		URLConnection conn6 = u6.openConnection(); 
		HttpURLConnection httpConn6 = (HttpURLConnection) conn6;
		int responseCode6 = httpConn6.getResponseCode();
		this.annotation_indeces.removeAllElements();                  // clear the existing annotation buffers
		this.annotation_values.removeAllElements();
		if(responseCode6 == HttpURLConnection.HTTP_OK)
		    {
			InputStream in6 = httpConn6.getInputStream(); 
			Reader reader6 = new InputStreamReader(in6);
			BufferedReader bufferedReader6 = new BufferedReader(reader6);
			String line6;                                       // annotations streamed in two-line pairs, first line is sample # (int), next line is annotation (string)
			int i = 0;
			
			while((line6 = bufferedReader6.readLine()) != null)
			    {
				if(!line6.equals(""))
				    {
					if(i%2 == 0) 
					    {
						Long tmpval6 = new Long(line6);
						annotation_indeces.addElement(tmpval6);
					    }
					else 
					    {
						String tmpval6 = new String(line6);
						annotation_values.addElement(tmpval6);
					    }
					i++;
				    }
			    }
			bufferedReader6.close();
		    } 
		httpConn6.disconnect();
		////////////////////////WAS COMMENTED ABOVE///////////////////////////////////////////
		
		
	    }
	catch (MalformedURLException e) {System.out.println("Malformed URL:" + e);}
	catch (IOException e) {System.out.println("IOException:" + e);}
	
	// tell children (ScopeCanvas) how many channels are available and send the signal & annotation vectors
	//Enumeration enum_child = this.children.elements();
	//while(enum_child.hasMoreElements()) 
	//  {
	//  CustomCanvas currentchild = (CustomCanvas) enum_child.nextElement();
	//  Vector multidimensional_vector = new Vector();
	//  multidimensional_vector.addElement(this.signal);
	//  multidimensional_vector.addElement(this.annotation_indeces);
	//  multidimensional_vector.addElement(this.annotation_values);
	//  multidimensional_vector.addElement(new Long(this.START_INDEX));
	//  currentchild.ChildUpdate(multidimensional_vector);
	//  }          
    }
    

  protected void drawlimits(Graphics2D g)     
    {

    }


  // draw the signal
  protected void drawSignal(Graphics2D g)     
    {
    if(this.signal.size() == 0) {return;}
    
    int baselineincrement = 0;

    int hiddensignals = 0;
    String temp; 
    //Code to keep track of hidden signals
    for(int v = 0; v<sigs.getSize(); v++)
	{
	    temp = (String)sigvals.elementAt(v);
	    if(temp.equals("0"))
		hiddensignals++;
	}

	
    // divide the canvas into vertical regions based on number of signals to be drawn
    int baseline_offset = (this.bot-this.top)/((this.active_channel_numbers.size()-hiddensignals)+1);   // note bot is bigger than top b/c of inverse y-axis numbering

    // use only the active channels for rendering
    for(int i=0; i < this.active_channel_numbers.size(); i++)
      {
    
      g.setColor(Color.BLUE);

      int this_baseline_offset;

      // space the signals vertically
      //if(i == 0)
	  this_baseline_offset = baseline_offset*(baselineincrement+1);
	  //else
	  //this_baseline_offset = baseline_offset*((i-hiddensignals)+1);

      // x starts at left edge of canvas (unless in movie mode)  
      int x = this.grid_x_threshold;    
      int index,first_index = 0;
      Double next, previous;
      int mapnext, mapprevious, j, maxval, startx, starty, stopper;
      String signame, tmpname, holder;
      String sigaction = "";
      Integer tmp2 = (Integer)(this.active_channel_numbers.elementAt(i));
      index = (int)tmp2.intValue();
      first_index = index-1;    // -1 since signals are 0-indexed but chan nums are 1-indexed
      next = ((Double) this.signal.elementAt(first_index));   
      //scale large signal values
      if(next >1.0)
	  next = next * .005;
      mapnext = (int) (this_baseline_offset - ((double)this.unitsperpixel_y_num/(double)this.unitsperpixel_y_den)*next.doubleValue()*this.Y_SCALE);
      maxval = this.signal.size();
      
      stopper = 0;
      startx = 0;
      starty = 0;
      String ckon;
      //code to handle the signal visibility pop-up menu
      if( popup_on_off == 0)
	  {
	      JCheckBoxMenuItem cbMenuItem;
	      CheckBoxListener cblistener;	    
	      submenu.removeAll();
	     
	      for(int z=0; z<sigs.getSize();z++)
		  {
		      holder = (String)sigs.getElementAt(z);		       
		      cbMenuItem = new JCheckBoxMenuItem(holder);
		      cblistener = new CheckBoxListener();
		      cbMenuItem.addItemListener(cblistener);
		      ckon = (String)sigvals.elementAt(z);
		      if(ckon.equals("0"))
			  cbMenuItem.setState(false);
		      else
			  cbMenuItem.setState(true);
		      submenu.add(cbMenuItem);
		  }
	      cbMenuItem = new JCheckBoxMenuItem("Show All");
	      cblistener = new CheckBoxListener();
	      cbMenuItem.addItemListener(cblistener);
	      cbMenuItem.setState(false);
	      submenu.add(cbMenuItem);

	      popup.revalidate();
	      popup.repaint();
	      popup_on_off = 1;
	  }

      // X zoomed in - expand
      if(X_SCALE >= 1) 
	{
        j = first_index + this.NUM_CHANNELS;
        while(j < maxval)   // signals are interleaved (TDM = time division multiplex)
          {
          mapprevious = mapnext;
          next = ((Double) this.signal.elementAt(j));
	  if(next >1.0)
	      next = next * .005;
	  signame = (String) this.signalnames.elementAt(j);
	
	  for(int k = 0; k<sigs.getSize(); k++)
	   {
	   tmpname = (String)sigs.getElementAt(k);
	   if(signame.equals(tmpname))
	       { 
	  	  sigaction = (String)sigvals.elementAt(k);
	  	  
	  	  break;
	       }
	   }
	  //baselineincrement++;
	  if(sigaction.equals("0"))
	      {
		  baselineincrement--;
		  break;
	      }
	  
	  
	  
	     
          mapnext = (int) (this_baseline_offset - ((double)this.unitsperpixel_y_num/(double)this.unitsperpixel_y_den)*next.doubleValue()*this.Y_SCALE);
	  g.drawLine(((int)this.X_SCALE*x), mapprevious, ((int)this.X_SCALE*(x+1)), mapnext);
	  if(stopper == 0){
	      startx = (int)this.X_SCALE*x;
	      starty = mapprevious; 
	      g.setColor(Color.BLACK);
	      g.drawString(signame, startx, starty+30);
	      //g.drawString(Integer.toString((int)this.START_INDEX), startx, starty+30);
	      
	      g.setColor(Color.BLUE);
	  }
	 
          x += 1;
          if(this.MOVIE_IS_PLAYING == true && (this.X_SCALE*x) > (this.grid_x_threshold)+this.MOVIE_PIXEL_OFFSET) {break;}
          j+= this.NUM_CHANNELS;
	  stopper = 1;
          }
        }          

      // X zoomed out - compress
      else
        {
        int X_SCALE_TMP = -this.X_SCALE;
	j = first_index + this.NUM_CHANNELS*X_SCALE_TMP;
        while(j < maxval)   // signals are interleaved (TDM = time division multiplex)
          {
          mapprevious = mapnext;
 	  next = (Double) this.signal.elementAt(j);
	  if(next >1.0)
	      next = next * .005;
	  signame = (String) this.signalnames.elementAt(j);
	  
	  for(int k = 0; k<sigs.getSize(); k++)
	      {
		  tmpname = (String)sigs.getElementAt(k);
		  if(signame.equals(tmpname))
		      { 
			  sigaction = (String)sigvals.elementAt(k);
			  
			  break;
		      }
	      }
	  //baselineincrement++;
	  if(sigaction.equals("0"))
	      {
		  baselineincrement--;
		  break;
	      }
	  


	  //this.signalnames.removeAllElements();
          mapnext = (int) (this_baseline_offset - ((double)this.unitsperpixel_y_num/(double)this.unitsperpixel_y_den)*next.doubleValue()*this.Y_SCALE);
          g.drawLine((x), mapprevious, ((x)+1), mapnext);
	  if(stopper == 0){
	      startx = x;
	      starty = mapprevious;
	      g.setColor(Color.BLACK);
	      g.drawString(signame, startx, starty+30);
	      //g.drawString(Integer.toString((int)this.START_INDEX), startx, starty+30);
	      g.setColor(Color.BLUE);
	  }
	 
          x += 1;
          if(this.MOVIE_IS_PLAYING == true && x > (this.grid_x_threshold)+this.MOVIE_PIXEL_OFFSET) {break;}
          j+= this.NUM_CHANNELS*X_SCALE_TMP;
	  stopper = 1;
          }
	}
      baselineincrement++;
	  // break;
      }  // end for loop
    //   this.signalnames.clear();
   }    // end drawSignal

    //ALI UNCOMMENTED BELOW//////////////////////////////////////////////////////
    public void drawAnnotations(Graphics2D g)
    { 
	int i = 0;
	Enumeration enum_ann_indeces = this.annotation_indeces.elements();
	while(enum_ann_indeces.hasMoreElements()) 
	    {
		Long currentindex = (Long) enum_ann_indeces.nextElement();
		int pixeloffset;
		if(this.X_SCALE < 0)
		    {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)/-X_SCALE + this.grid_x_threshold);}
		else
		    {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)*X_SCALE + this.grid_x_threshold);}
		if(this.MOVIE_IS_PLAYING == true && pixeloffset > this.grid_x_threshold+this.MOVIE_PIXEL_OFFSET) {return;}
		String current_annotation = (String)this.annotation_values.elementAt(i);
		if(current_annotation.equals("N") || current_annotation.equals(")") || current_annotation.equals("("))
		    {g.setColor(Color.GRAY);}
		else
		    {g.setColor(Color.RED);}
		
		//has this annotation been rendered on ScopeCanvas child before?
		    if(this.renderedannotations.indexOf(currentindex) == -1)  // new! update child with index and annotation type
			{
			    while(this.renderedannotations.size() > this.FIFO_DEPTH)
				{
				    this.renderedannotations.removeElementAt(0);
				    this.renderedannotations.trimToSize();
				}
			    this.renderedannotations.addElement(currentindex);
			    Enumeration enum_child = this.children.elements();
			    while(enum_child.hasMoreElements()) 
				{          
				    CustomCanvas currentchild = (CustomCanvas) enum_child.nextElement();
				    currentchild.ChildUpdate(currentindex,current_annotation);
				}          
			}
		
		if(!current_annotation.equals("="))
		    {
			g.drawLine(pixeloffset,this.bot-this.grid_y_threshold,pixeloffset,0);
			g.setColor(Color.BLACK);
			g.drawString(current_annotation,pixeloffset,this.bot-this.grid_y_threshold);
		    }
	  
		i++;
	      
	    }  
    }
    ////////////////////////////WAS COMMENTED ABOVE//////////////////////////////////////////////////

   public void drawTimeStamps(Graphics2D g)
     {
     g.setColor(Color.BLACK);
     float total_secs_begin = (float)this.START_INDEX/this.SAMPLING_FREQUENCY;    
     int days_begin = (int)(total_secs_begin/86400);
     int hrs_begin = (int)((total_secs_begin - days_begin*86400)/3600);
     int mins_begin = (int)((total_secs_begin - days_begin*86400 - hrs_begin*3600)/60);
     float secs_begin = total_secs_begin - -days_begin*86400 - hrs_begin*3600 - mins_begin*60;
     int secs = (int)(secs_begin + .5);
     g.drawString(days_begin + ":" + hrs_begin + ":" + mins_begin + ":" + secs, this.grid_x_threshold+5,this.bot-4/*15*/);
     g.drawString("Grid Intervals: 0.2 sec, 0.5mV",this.grid_x_threshold+695, this.bot-4);
     g.drawString("Record:" +this.dbid +"/"+this.recid,this.grid_x_threshold+170, this.bot-4);
       
     float total_secs_end;
     if(this.X_SCALE < 0)        // x-axis expanded - time increased at end by factor of -X_SCALE
	 {total_secs_end = total_secs_begin + -X_SCALE*(this.rightx-(this.grid_x_threshold))/this.SAMPLING_FREQUENCY;}
     else                       // x-axis compressed or equal to default 1 (no zoom)
	 {total_secs_end = total_secs_begin + (this.rightx-(this.grid_x_threshold))/(X_SCALE*this.SAMPLING_FREQUENCY);} 

     FontMetrics fm = g.getFontMetrics();      //get the font metrics (used for string sizes)

     int days_end = (int)(total_secs_end/86400);      
     int hrs_end = (int)((total_secs_end - days_end*86400)/3600);
     int mins_end = (int)((total_secs_end - days_end*86400 - hrs_end*3600)/60);
     float secs_end = total_secs_end - days_end*86400 - hrs_end*3600 - mins_end*60;
     secs = (int)(secs_end + .5);
     String tmp = days_end + ":" + hrs_end + ":" + mins_end + ":" + secs;
     g.drawString(tmp, this.rightx-fm.stringWidth(tmp)-5,this.bot-4/*15*/);

     float timespan_secs = total_secs_end-total_secs_begin;
     secs = (int)(timespan_secs + .5);
     int hrs_span = (int)(timespan_secs/3600);
     int mins_span = (int)((timespan_secs-hrs_span*3600)/60);
     float secs_span = timespan_secs-hrs_span*3600-mins_span*60;
     tmp = "timespan: " + hrs_span + ":" + mins_span + ":" + secs;
     g.drawString(tmp, (this.rightx-fm.stringWidth(tmp)-5)/2,this.bot-4);

     this.gridx  = (int)((950/((int)(timespan_secs/.2)))+.5);
     g.setColor(Color.pink);
     this.drawGrid(g, this.gridx, this.gridy);

     }


  //Methods required by the MouseInputListener interface.
  public void mousePressed(MouseEvent e) 
     { }


  public void mouseMoved(MouseEvent e) 
    { 
    if(this.MOVIE_IS_PLAYING == true) {return;}

    int x = e.getX();
    int y = e.getY();
    if(point2 == null) 
      {
      point2 = new Point(x,y);
      }
    else
      {
      point2.x = x;
      point2.y = y;
      }

    //    if(this.ADDING_NEW_ANNOTATION == true || this.DELETING_ANNOTATION == true) 
    // {
      // are we close to a new annotation? ("close" = within 5 pixels on either side)
    //  this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = -1;
    // Enumeration enum_ann_indeces = this.annotation_indeces.elements();
    // while(enum_ann_indeces.hasMoreElements()) 
    //   {
    //   Long currentindex = (Long) enum_ann_indeces.nextElement();
    //   int pixeloffset;
    //   if(this.X_SCALE < 0)
    //	  {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)/-X_SCALE + this.grid_x_threshold);}
    //   else
    //	  {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)*X_SCALE + this.grid_x_threshold);}
    //       if(point2.x >= pixeloffset-5 && point2.x <= pixeloffset+5)
    //	  {
    //     this.CURRENTLY_HIGHLIGHTED_ANN_INDEX = currentindex.longValue();

          // if the user has moved the mouse to a new annotation, erase the previously clicked one 
    //          if(this.CURRENTLY_HIGHLIGHTED_ANN_INDEX != this.CURRENTLY_CLICKED_ANN_INDEX) 
    //       {this.CURRENTLY_CLICKED_ANN_INDEX = -1;}

    //          break;
    //      }
    //   }  
    //  }

    this.repaint();       // calls PaintComponent method 
    }


  public void mouseExited(MouseEvent e) 
    { 
    this.point = null; this.point2 = null; this.repaint();
    } 


  public void mouseClicked(MouseEvent e) 
    { 
    if(this.MOVIE_IS_PLAYING == true) {return;}
    //  if (e.isPopupTrigger()) {
    //	popup.show(e.getComponent(), e.getX(), e.getY());
	// }
    int x = e.getX();
    int y = e.getY();

    switch(e.getModifiers()) 
        {
        // LEFT BUTTON
        case InputEvent.BUTTON1_MASK: 
          {   
          break;
          }
      
        // MIDDLE BUTTON
        case InputEvent.BUTTON2_MASK: 
          {  
          return;
          }
    
        // RIGHT BUTTON
        case InputEvent.BUTTON3_MASK: 
          {  
	  if(this.popup != null)
	    {
	    popup.show(e.getComponent(),x,y);
	    e.consume();
            }
	  return;
          }



	}

    // ignore the event if it is outside the signal range
    //if(x < this.grid_x_threshold || x >= (this.signal.size()/this.active_channel_numbers.size()) ) {return;}

    //if(point == null) {point = new Point(x,y);}
    //point.x = x; point.y = y;

    //if(point2 == null) {point2 = new Point(x,y);}
    //point2.x = x; point2.y = y;

    // is the user clicking to add a new annotation?
    //if(this.ADDING_NEW_ANNOTATION == true)
    //  {
    //  long time;
    //  if(this.X_SCALE < 0)
    //	{time = this.START_INDEX + (x - this.grid_x_threshold)*-X_SCALE;}
    // else
    //	{time = this.START_INDEX + (x - this.grid_x_threshold)/X_SCALE;}

      // may not overwrite an existing annotation
    // if(this.renderedannotations.indexOf(new Long(time)) == -1)  // no annot here - go ahead 
    //	{
    //	this.annotation_indeces.addElement(new Long(time));
    //	this.annotation_values.addElement(this.active_annotation);
    //   this.add_annotation_to_server(time, this.active_annotation);
    //	}
    //this.ADDING_NEW_ANNOTATION = false;
    // this.repaint();
    // return;
    //}

    // is the user clicking to delete an annotation?
    //if(this.DELETING_ANNOTATION == true)
    // {
    // Enumeration enum_ann_indeces = this.annotation_indeces.elements();
    // while(enum_ann_indeces.hasMoreElements()) 
    //   {
    //   Long currentindex = (Long) enum_ann_indeces.nextElement();
    //   int pixeloffset;
    //   if(this.X_SCALE < 0)
    //	  {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)/-X_SCALE + this.grid_x_threshold);}
    //   else
    //	  {pixeloffset = (int)((currentindex.longValue()-this.START_INDEX)*X_SCALE + this.grid_x_threshold);}
    //   if(point.x >= pixeloffset-5 && point.x <= pixeloffset+5)
    //	  {
    //	  int tmpindex = this.annotation_indeces.indexOf(currentindex);
    //	  this.delete_annotation_from_server(currentindex.longValue());
    //	  this.annotation_indeces.removeElementAt(tmpindex);
    //	  this.annotation_values.removeElementAt(tmpindex);
    //     break;
    //     }
    //   }  
    // this.DELETING_ANNOTATION = false;
    // this.repaint();
    // return;
    // }

    this.repaint();       // calls PaintComponent method
    }



}  // end MultiChannel_Movie_Canvas class




class TimerInterruptGenerator implements ActionListener
  {
  Timer timer;
  MultiChannel_Movie_Canvas parent;

  public void actionPerformed(ActionEvent evt) {parent.timer_interrupt();}
  
  public TimerInterruptGenerator(MultiChannel_Movie_Canvas parent)
    {
    timer = new Timer(1000,this);
    this.parent = parent;
    }

  public void start()
    {timer.start();}

  public void stop()
    {timer.stop();}

  public void setDelay(int time_in_ms)
    {timer.setDelay(time_in_ms);}
  }
