// file: OutputPanel.java
//

// include the necessary system files
//
import java.awt.*;
import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Event;
import java.awt.GridBagLayout;
import javax.swing.border.*;
import java.awt.BorderLayout;

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

// class: OutputPanel
//
// this class implements a tool which controls the input to a pole-zero
// map it allows the user to place poles and zeros.
//
public class OutputPanel extends SubPanel implements Constants {
    
    public ImpulseResponse impulse_response;
    public  MagResponse mag_response;
    public  PhaseResponse phase_response;
    private ThreeDResponse three_d;
    private SystemPolynomial sys_poly;
    
    // variable for the output type
    //
    private int design_type = Constants.DEFAULT_DESIGN;
    
    // array to hold the poles and zeros to be evaluated
    //
    private PoleZero pz_array[];
    
    // frequency range
    //
    private double max_frequency = Constants.DEFAULT_SAMPLE_FREQ;
    
    //    private JPanel container_00 = new JPanel();
    
    Border border;
    
    // declare the default fonts
    //
    Font currentFont = getFont();
    Font newFont = new Font(currentFont.getName(), currentFont.getStyle(), 12);
    
    //*****************************************************************
    //
    // constructor methods
    //
    //*****************************************************************
    
    // method: OutputPanel
    //
    // parameters: none
    // 
    // this method constructs the default OutputPanel object
    //
    public OutputPanel(int type, double frequency, PoleZero pz_array_a[]) {
	
	// call the super-class constructor
	//
	super();
	
	// create a border around the input panel
	//
	setBorder(BorderFactory.createEtchedBorder());
	
	// set the design type
	//
	design_type = type;
	
	// set a pointer to the array of poles and zeros
	//
	pz_array = pz_array_a;
	
	// run the initializations
	//
	this.add_components();
    }
    
    
    //***************************************************************
    //
    // private methods
    //
    //***************************************************************
    
    
    // method: add_components
    //
    // parameters: none
    // 
    // this method initializes the gui components of the class
    //
    // returns: boolean
    //  
    private boolean add_components() {
	
	border =  new TitledBorder(new EmptyBorder(0,0,0,0),"Poles",
				   TitledBorder.LEFT,TitledBorder.LEFT,
				   new Font(currentFont.getName(), 
					    currentFont.getStyle(), 12),Color.black);
	
	// instantiate each of the output components
	//
	impulse_response = new ImpulseResponse(pz_array, design_type);
	mag_response = new MagResponse(max_frequency, pz_array, design_type);
	phase_response = new PhaseResponse(max_frequency, pz_array, design_type);
	three_d = new ThreeDResponse(max_frequency, pz_array, design_type);
	sys_poly = new SystemPolynomial(max_frequency, pz_array, design_type);
	
	// set the background colors for each of the output plots
	//
	impulse_response.setBackground(Color.white);
	mag_response.setBackground(Color.white);
	phase_response.setBackground(Color.white);
	
	// add border to impulse response graph
	border =  new TitledBorder(new EmptyBorder(0,0,0,0),"Impulse Response(Real)",
				   TitledBorder.LEFT,TitledBorder.LEFT,
				   new Font(currentFont.getName(), 
					    currentFont.getStyle(), 12),Color.black);
	
	impulse_response.setBorder(border);
	// place the output panels panel to the lower-left
	//
	constrain(this, impulse_response, 0, 0, 1, 1, GridBagConstraints.BOTH,
		  GridBagConstraints.WEST, 1.0, 1.0, 5,5,5,5);
	
	// add border to magnitude response graph
	border =  new TitledBorder(new EmptyBorder(0,0,0,0),"Magnitude Response",
				   TitledBorder.LEFT,TitledBorder.LEFT,
				   new Font(currentFont.getName(), 
					    currentFont.getStyle(), 12),Color.black);
	
	mag_response.setBorder(border);
	constrain(this, mag_response, 1, 0, 1, 1, GridBagConstraints.BOTH,
		  GridBagConstraints.CENTER, 1.0, 1.0, 5,5,5,5);
	
	
	// add border to phase response graph
	border =  new TitledBorder(new EmptyBorder(0,0,0,0),"Phase Response",
				   TitledBorder.LEFT,TitledBorder.LEFT,
				   new Font(currentFont.getName(), 
					    currentFont.getStyle(), 12),Color.black);
	
	phase_response.setBorder(border);
	constrain(this, phase_response, 2, 0, 1, 1, GridBagConstraints.BOTH,
		  GridBagConstraints.EAST, 1.0, 1.0,5,5,5,5);
	
	// exit gracefully
	//
	return true;
	
    }
    
    
    //****************************************************************
    //
    // public methods
    //
    //****************************************************************
    
    
    // method start
    //
    // parameters: none
    //
    // this method starts or restarts the threaded object
    //
    // returns: none
    //
    public void start () {
	
	// start the threaded sub-components
	//
	mag_response.start();
	phase_response.start();
	impulse_response.start();
	three_d.start();
	
    }
    
    
    // method stop
    //
    // parameters: none
    //
    // this method stops the threaded object
    //
    // returns: none
    //
    public void stop () {
	
	// stop the components of this object
	//
	mag_response.stop();
	phase_response.stop();
	impulse_response.stop();
	three_d.stop();
	
    }
    
    
    // method start_3d
    //
    // parameters: none
    //
    // this method turns on the 3d analysis capabilities
    //
    // returns: none
    //
    public void start_3d() {
	
	three_d.setVisible(true);
	
    }
    
    
    // method stop_3d
    //
    // parameters: none
    //
    // this method turns off the 3d analysis capabilities
    //
    // returns: none
    //
    public void stop_3d() {
	
	three_d.setVisible(false);
    }
    
    
    // method: update_screen
    //
    // parameters: (none)
    // 
    // this method sets the update_flag causing a repaint of the
    // canvas
    //
    // returns: boolean
    //
    public boolean update_screen() {
	
	// update each sub-component
	//
	mag_response.update_screen();
	phase_response.update_screen();
	impulse_response.update_screen();
	sys_poly.update_screen();
	
	// exit gracefully
	//
	return true;
	
    }
    
    // method: partial_update
    //
    // parameters: (none)
    // 
    // this method only updates a portion of this panel
    //
    // returns: boolean
    //
    public boolean partial_update() {
	
	// update each sub-component
	//
	mag_response.update_screen();
	
	// exit gracefully
	//
	return true;
	
    }  
    
    
    // method: set_pz_array
    //
    // parameters:
    //     PoleZero pz_array_a[]: (input) array of poles and zeros
    // 
    // this method sets the pz_array to point to the input variable
    //
    // returns: boolean
    //
    public boolean set_pz_array(PoleZero pz_array_a[]) {
	
	// set the pointer
	//
	pz_array = pz_array_a;
	
	// set the panels to each point to this array
	//
	mag_response.set_pz_array(pz_array);
	phase_response.set_pz_array(pz_array);
	three_d.set_pz_array(pz_array);
	impulse_response.set_pz_array(pz_array);
	sys_poly.set_pz_array(pz_array);
	
	// exit gracefully
	//
	return true;
	
    }
    
    
    // method: MinimumSize 
    //
    // parameters: (none)
    //
    // this is a method to set the preferred size of this component
    //
    // returns: Dimension
    //
    public synchronized Dimension MinimumSize() {
	
	// create new Dimension object and return it
	//
	return(new Dimension(Constants.MINIMUM_WIDTH,
			     Constants.MINIMUM_HEIGHT));
    }
    
    
    // method: set_frequency
    //
    // parameters:
    //     double frequency: (input) frequency input
    // 
    // this method sets the sample frequency or maximum frequency
    //
    // returns: boolean
    //
    public boolean set_frequency(double frequency) {
	
	// set the frequency
	//
	max_frequency = frequency;
	
	// set the frequency in all of the sub-components
	//
	mag_response.set_frequency(frequency);
	phase_response.set_frequency(frequency);
	impulse_response.set_frequency(frequency);
	three_d.set_frequency(frequency);
	sys_poly.set_frequency(frequency);
	
	// exit gracefully
	//
	return true;
	
    }
    
    
    // method: set_dc_gain
    //
    // parameters:
    //     double new_dc_gain: (input) dc gain
    // 
    // this method sets the dc gain of the filter
    //
    // returns: boolean
    //
    public boolean set_dc_gain(double new_dc_gain) {
	
	// set the frequency in all of the sub-components
	//
	mag_response.set_dc_gain(new_dc_gain);
	impulse_response.set_dc_gain(new_dc_gain);
	three_d.set_dc_gain(new_dc_gain);
	sys_poly.set_dc_gain(new_dc_gain);
	
	// exit gracefully
	//
	return true;
	
    }
    
    
    // method: set_design_type 
    //
    // parameters:
    //     integer new_type: (input) design type to change to
    //
    // this is a method to set the design type.  the design type will
    // be set to the value passed in to new_type
    //
    // returns: boolean
    //
    public boolean set_design_type(int new_type) {
	
	// make sure the new_type is valid, then set the design_type
	// variable, and return a boolean value which indicates whether
	// or not the new_type was valid.  note:  this assumes that 
	// the design_type is currently a valid value
	//
	if((new_type == Constants.DIGITAL) || (new_type == Constants.ANALOG)) {
	    design_type = new_type;
	    mag_response.set_design_type(new_type);
	    phase_response.set_design_type(new_type);
	    impulse_response.set_design_type(new_type);
	    three_d.set_design_type(new_type);
	    sys_poly.set_design_type(new_type);
	    return true;
	}
	else {
	    return false;
	}
    }
    
} // end class OutputPanel
