// file: PzmapPanel.java
//

// include the necessary system files
//
import java.awt.*;
import java.lang.*;
import javax.swing.*;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.Event;
import java.awt.event.*;
import javax.swing.event.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

// include the necessary local files
//
//import Constants;

// class: PzmapPanel
//
// this class implements a canvas which holds either a digital or 
// analog pole-zero map and displays the location of poles and
// zeros on that map.
//
public class PzmapPanel extends SubPanel 
    implements  ActionListener, Constants {
    
    // set class constants
    //
    
    // timer
    public final static int SLEEP_TIME = 600;
    private Timer timer;
    
    // text field length
    //
    public final static int TEXT_FIELD_LENGTH = 8;
    
    // variable to hold the current sample frequency for 
    // digital designs
    //
    private double sample_frequency = Constants.DEFAULT_SAMPLE_FREQ;
    
    // set up a thread to take care of updating the display
    //
    
    // set up a flag to determine if the display needs to be
    // updated and initialize it to false
    //
    private boolean update_flag = false;  
    
    // type of design
    //
    private int map_type = Constants.DEFAULT_DESIGN;
    
    // declare gui components
    //
    private String sf_string = new String("Sample Frequency");
    private String range_string = new String("Frequency Range");
    private String dc_gain_string = new String("DC Gain");   
    private JLabel sf_range_label;
    private JLabel dc_gain_label = new JLabel(dc_gain_string);  
    private Pzmap pz_map;
    //private JTextField sf_area = new 
    //  JTextField(String.valueOf(Constants.DEFAULT_SAMPLE_FREQ), 
    //    TEXT_FIELD_LENGTH);
    //private JTextField dc_gain_area = new 
    //  JTextField(String.valueOf(1), TEXT_FIELD_LENGTH);  
    
    // output panel to control and data display panel to control
    //
    private OutputPanel output;
    private DataDisplayPanel data_display;
    
    // set up an array of poles and zeros
    //
    private PoleZero pz_array[] = new PoleZero[Constants.MAX_ARRAY_SIZE];
    
    // dc_gain parameter
    //
    private double dc_gain = 1.0;
    
    // indicates state of 3d analysis
    //
    private boolean threeD_flag = false;
    
    //*****************************************************************
    //
    // constructor methods
    //
    //*****************************************************************
    
    // method: PzmapPanel
    //
    // parameters: none
    // 
    // this method constructs a Pzmap of the default type
    //
    public PzmapPanel(OutputPanel output_a, DataDisplayPanel display_a,
		      int type) {
	
	// call the super-class's constructor
	//
	
	super();
	
	// set the design_type
	//
	map_type = type;
	
	// set the output panel and data display panel
	//
	output = output_a;
	data_display = display_a;
	
	// set the design_type for the map
	//
	pz_map = new Pzmap(map_type, pz_array, output, data_display);
	
	// set the pole zero array in output to point to
	// the one from this application
	//
	output.set_pz_array(pz_array);
	
	// add components to the display
	//
	this.add_components();
	
	
	// cause manual repaint of the canvas
	//
	update_flag = true;
	output.update_screen();
	
	timer = new Timer(SLEEP_TIME, new ActionListener() {
	    public void actionPerformed(ActionEvent evt) {
		// see if map needs updating, if so then call the paint method
		// then reset the flag
		//
		if (update_flag == true) {
		    repaint();
		    update_flag = false;
		}
	    }
	} );
	this.start();
    }
    
    
    
    
    //***************************************************************
    //
    // private methods
    //
    //***************************************************************
    
    
    // method: add_components
    //
    // parameters: none
    // 
    // this method initializes the gui components of the class
    //
    // returns: boolean
    //  
    private boolean add_components() {
	
	// initialize the gui components
	//
	pz_map.setBackground(Color.white);
	
	// decide if the sample frequency area needs to be disabled
	//
	
	// place the data_input panel to the upper-left
	//
	constrain(this, pz_map, 0,0, GridBagConstraints.REMAINDER,
		  GridBagConstraints.REMAINDER, GridBagConstraints.BOTH,
		  GridBagConstraints.NORTHWEST, 15.2, 1.0, 3,3,3,3);
	
	if (map_type == Constants.DIGITAL) {
	    sf_range_label = new JLabel(sf_string);
	}
	else {
	    sf_range_label = new JLabel(range_string);
	}

	// exit gracefully
	//
	return true;
	
    }
    
    //****************************************************************
    //
    // public methods
    //
    //****************************************************************
    
    
    // method start
    //
    // parameters: none
    //
    // this method starts or restarts the threaded applet
    //
    // returns: none
    //
    public void start () {
	
	if( ! timer.isRunning()) {
	    pz_map.start();
	    timer.start();
	}
	if (threeD_flag) {
	    output.start_3d();
	    threeD_flag = true;
	}
	
	update_flag = true;
    }
    
    
    // method stop
    //
    // parameters: none
    //
    // this method stops the threaded applet
    //
    // returns: none
    //
    public void stop () {
	
	// stop the components of this applet
	//
	if(timer.isRunning()) {
	    pz_map.stop();
	    timer.stop();
	    output.stop_3d();
	}
	
    }
    
    
    // method: add_pole
    //
    // parameters: (none)
    //
    // this is a method to add a pole to the pzmap
    //
    // returns: boolean
    //
    public boolean add_pole(double frequency, double bandwidth) {
	
	// check design type to see what to send the
	// display area
	//
	if (map_type == Constants.DIGITAL) {
	    
	    // add the pole to the map and to the data panel
	    // then update the output panel
	    //
	    pz_map.add_pole(frequency, bandwidth);      
	    data_display.add_pole(frequency, bandwidth);
	}
	else {
	    
	    // add the pole to the map and to the data panel
	    // then update the output panel
	    //
	    pz_map.add_pole(frequency, bandwidth);
	    data_display.add_pole(frequency, bandwidth);
	}
	
	// update the screen
	//
	output.update_screen();
	
	// exit gracefully
	//
	return true;
    }
    
    
    // method: add_zero
    //
    // parameters: (none)
    //
    // this is a method to add a zero to the pzmap
    //
    // returns: boolean
    //
    public boolean add_zero(double frequency, double bandwidth) {
	
	if (map_type == Constants.DIGITAL) {
	    
	    // add the pole to the map and to the data panel
	    // then update the output panel
	    //
	    pz_map.add_zero(frequency, bandwidth);      
	    data_display.add_zero(frequency, bandwidth);
	}
	else {
	    
	    // add the pole to the map and to the data panel
	    // then update the output panel
	    //
	    pz_map.add_zero(frequency, bandwidth);
	    data_display.add_zero(frequency, bandwidth);
	}
	
	// update the output screen
	//
	output.update_screen();
	
	// exit gracefully
	//
	return true;
    }
    
    
    // method: clear_all
    //
    // parameters: (none)
    //
    // this is a method to clear all poles and zeros from the map
    //
    // returns: boolean
    //
    public boolean clear_all() {
	
	// add the zero to the map and to the data panel
	// then update the output screen
	//
	pz_map.clear_all();
	data_display.clear_all();
	output.update_screen();
	
	// exit gracefully
	//
	return true;
    }
    
    
    // method: set_sample_frequency
    //
    // parameters:
    //     int new_freq: (input) sample frequency to change to
    //
    // this is a method to set the sample frequency.  This has an
    // effect only on the digital map
    //
    // returns: boolean
    //
    public boolean set_sample_frequency (double new_freq) {
	
	// make sure the sample frequency is in the proper range
	//
	if (0.0 < new_freq) {
	    
	    // set the sample frequency to the input frequency and
	    // reset the graphics
	    //
	    this.sample_frequency = new_freq;
	    pz_map.set_sample_frequency(new_freq);
	    output.set_frequency(new_freq);
	    update_flag = true;
	    
	    // exit gracefully
	    //
	    return true;
	}
	else {
	    
	    // exit with error
	    //
	    return false;
	}
    }
    
    
    // method: set_dc_gain
    //
    // parameters:
    //     int new_dc_gain: (input) dc gain to switch to
    //
    // this is a method to set the dc gain of the filter
    //
    // returns: boolean
    //
    public boolean set_dc_gain (double new_dc_gain) {
	
	// make sure the dc gain is in the proper range
	//
	if (0.0 <= new_dc_gain) {
	    
	    // set the sample frequency to the input frequency and
	    // reset the graphics
	    //
	    this.dc_gain = new_dc_gain;
	    output.set_dc_gain(new_dc_gain);
	    update_flag = true;
	    
	    // exit gracefully
	    //
	    return true;
	}
	else {
	    
	    // exit with error
	    //
	    return false;
	}
    }
    
    
    // method: set_map_type 
    //
    // parameters:
    //     int new_type: (input) map type to change to
    //
    // this is a method to set the map type.  the map type will
    // be set to the value passed in to new_type
    //
    // returns: boolean
    //
    public boolean set_map_type(int new_type) {
	
	// make sure the new_type is valid, then set the map_type
	// variable, and return a boolean value which indicates whether
	// or not the new_type was valid.  note:  this assumes that 
	// the map_type is currently a valid value
	//
	if((new_type == Constants.DIGITAL) || (new_type == Constants.ANALOG)) {
	    
	    // set the appropriate variables
	    //
	    this.map_type = new_type;
	    pz_map.set_map_type(this.map_type);
	    data_display.set_design_type(this.map_type);
	    
	    // set the labels for input
	    //
	    if (new_type == Constants.DIGITAL) {
		sf_range_label.setText(sf_string);
	    }
	    else {
		sf_range_label.setText(range_string);
	    }
	    
	    // cause a repaint of the screen on the next thread cycle
	    //
	    update_flag = true;
	    
	    // update the output panel
	    //
	    output.update_screen();
	    
	    // exit gracefully
	    //
	    return true;
	}
	else {
	    
	    // exit with error
	    //
	    return false;
	}
    }
    
    public void set_start3d() {
	output.start_3d();
	threeD_flag = false;
    }
    
    
    
    //*****************************************************************
    //
    // event handler methods
    //
    //*****************************************************************
    
    // method: handleEvent
    //
    // parameters: 
    //     Event event: (input) an Event object indicating the event to handle
    //
    // this method handles the various interrupt events that may occur in this
    // component
    //
    // returns: boolean
    //
    
    public void actionPerformed(ActionEvent event) {
    }
    
} // end class PzmapPanel
