//PlaneWave_State.java
import java.util.*;


public class PlaneWave_State {
    //public static final double epsilon0 = 8.8541878176E-12; //Units: F/m
    // Approximate epsilon0 value consistent with approximate velocity
    public static final double epsilon0 = 8.841941286E-12; //Units: F/m
    public static final double mu0 = 1.25663706144E-6; //Units H/m
    //private static final double c = 1.0/Math.sqrt(epsilon0*mu0);
    private static final double c = 3.0E8; // m/s - apprximate light velocity
    double frequency, angular_frequency, wavelength, conductivity, phase_velocity, period;
    double alpha, beta; //attentuation coefficient and the wave vector
    public double Ex, Exref, Exref0, Ey, Hy, Phase, Phase_degree; //Amplitudes of E-Field in x and H-Field y directions
    double epsilon_r, mu_r; //relative permeability and permitivity
    double zpos[]; //position of reference planes in wavelengths. The call to PlaneWaveCanvas needs to convert it to meters.
    double loss_tangent;
    double skin_depth, skin_depth_wavelength;
    Complex wave_impedance, wave_impedance_0;
    double wave_impedance_mag, wave_impedance_mag_0, wave_impedance_phase;
    double total_length, window_area;//total_length in wavelengths, window_area in m^2
    double wt;
    double x[];
    double efield[], hfield[];
    int NPointsZ, NPointsT, DeltaT, CurrentTime, TotalTime;
    double  Phix, Phiy;
    int current_z;
    boolean RESET;
    public int SleepTime;
    public boolean IsLinear, IsElliptical, IsCircular, IsLeft, IsRight;
    
    public boolean LicenseExpired;
    public int this_month, today_week, this_year, this_hour, this_minute, today_month, 
	       today_year,this_zone, saving_time;
    GregorianCalendar Greg = new GregorianCalendar();

    
    public PlaneWave_State(){    
	//Independent Variables
	frequency = 1.0E9;
        period = 1.0/frequency;
	angular_frequency = 2.0*Math.PI*frequency;
	conductivity = 0.0;
	epsilon_r = 1.0;
	mu_r = 1.0;
	wavelength = EMF.getWaveLength(epsilon_r,mu_r,conductivity,angular_frequency); 
	NPointsZ = 361;
	NPointsT = 361;
	//NPointsZ = 181;
	//NPointsT = 181;
	
        DeltaT = 5;
	
        CurrentTime = 0;
        TotalTime = 0;
        
	wave_impedance = new Complex(Math.sqrt((mu_r*mu0)/(epsilon_r*epsilon0)),0.0);
	wave_impedance_0 = new Complex(Math.sqrt((mu0)/(epsilon0)),0.0);
	wave_impedance_mag_0 = wave_impedance_0.Magnitude();	
        
        wave_impedance_mag = wave_impedance.Magnitude();
	wave_impedance_phase = wave_impedance.Arg2();
	Hy = Ex/wave_impedance_mag_0;
        
        Phase = 0.0;
        
	SleepTime = 50;
        
	Ex = 1.0;
        Exref = 1.0;
        Exref0 = 1.0;
        Ey = 1.0;
        
	Hy = Ex/Math.sqrt(epsilon0*mu0);
	Phix = 0.0;
	current_z = 0;
	total_length = 1.0; //units of wavelength
	window_area = 1.0; // units of m^2
        
        IsLinear = true;
        IsElliptical = false;
        IsCircular = false;
        IsLeft = false;
        IsRight = false;
        
	RESET = false;
	//Memory allocations
	efield = new double[NPointsZ];
	hfield = new double[NPointsZ];
	
	x = new double[NPointsZ];
	ignition(); //Dependent variables
	scan_wave();
	zpos = new double[2];
	zpos[0] = 0.0 * total_length;
	zpos[1] = 1.0 * total_length;
	
	this_month = Greg.get(Calendar.MONTH);
	//System.out.println("  This is the month = "+this_month);
	today_week = Greg.get(Calendar.DAY_OF_WEEK);
	//System.out.println("  This is the day_week = "+today_week);
	this_year = Greg.get(Calendar.YEAR);
	this_hour = Greg.get(Calendar.HOUR_OF_DAY);
	//System.out.println("  This is the year = "+this_year);
	this_minute = Greg.get(Calendar.MINUTE);
	//System.out.println("  This is the minute = "+this_minute);
	today_month = Greg.get(Calendar.DAY_OF_MONTH);
	//System.out.println("  This is the day_month = "+today_month);
	today_year = Greg.get(Calendar.DAY_OF_YEAR);
	//System.out.println("  This is the day_year = "+today_year);
	this_zone = Greg.get(Calendar.ZONE_OFFSET);
	//System.out.println("  This is the zone_offset = "+this_zone/3600000);
	saving_time = Greg.get(Calendar.DST_OFFSET);
	//System.out.println("  This is the dst_offset = "+saving_time/3600000);

    }
    
    public synchronized void ignition(){
	//Dependent Variables
        period = 1.0/frequency;
	angular_frequency = 2.0 * Math.PI * frequency;
	wavelength = EMF.getWaveLength(epsilon_r,mu_r,conductivity,angular_frequency);
	phase_velocity = EMF.getPhaseVelocity(epsilon_r,mu_r,conductivity,angular_frequency);
	if(conductivity/(angular_frequency*epsilon_r*epsilon0) < 1.0e-6){
	    alpha = 0.5*conductivity*Math.sqrt(mu0*mu_r/(epsilon0*epsilon_r));
	    //double test =Math.pow(1.0+Math.pow((conductivity/(angular_frequency*epsilon_r*epsilon0)),2.0),0.5);
	    //System.out.println(alpha+"  *  ");
	}
	else{
	    alpha = EMF.getAlpha(epsilon_r,mu_r,conductivity,angular_frequency);
	    //double test =Math.pow(1.0+Math.pow((conductivity/(angular_frequency*epsilon_r*epsilon0)),2.0),0.5);
	    //System.out.println(alpha+"  **  "+test);
	}
	beta =  EMF.getBeta(epsilon_r,mu_r,conductivity,angular_frequency);
	
	if(alpha > 0.0){
	    skin_depth = 1.0/alpha;
            skin_depth_wavelength = skin_depth/wavelength; 
	}
	else {
	    skin_depth = Double.POSITIVE_INFINITY;
            skin_depth_wavelength = Double.POSITIVE_INFINITY;
        }
	wt = 2.0*Math.PI*CurrentTime/NPointsT;
	wave_impedance = EMF.getWaveImpedance(epsilon_r,mu_r,conductivity,angular_frequency);
	wave_impedance_mag = wave_impedance.Magnitude();
	wave_impedance_phase = wave_impedance.Arg2();
	//Hy = Ex/wave_impedance_mag_0;
        
        if(Ex != Ey){
            if(Phase_degree == 0.0 || Phase_degree == 180.0 || Phase_degree == - 180.0){
                IsLinear = true;
                IsElliptical = false;
                IsCircular = false;
                IsLeft = false;
                IsRight = false;
            }
            else{
                IsLinear = false;
                IsElliptical = true;
                IsCircular = false;
                if(Phase_degree < 0.0){
                    IsLeft = false;
                    IsRight = true;
                }
                else{
                    IsLeft = true;
                    IsRight = false;
                }
            }
        }
        else{
            if(Phase_degree == 90.0 || Phase_degree == -90.0){
                IsLinear = false;
                IsElliptical = false;
                IsCircular = true;
                if(Phase_degree < 0.0){
                    IsLeft = false;
                    IsRight = true;
                }
                else{
                    IsLeft = true;
                    IsRight = false;
                }
            }
            else if(Phase_degree == 0.0 || Phase_degree == 180.0 || Phase_degree == - 180.0){
                IsLinear = true;
                IsElliptical = false;
                IsCircular = false;
                IsLeft = false;
                IsRight = false;
            }
            else{
                IsLinear = false;
                IsElliptical = true;
                IsCircular = false;
                if(Phase_degree < 0.0){
                    IsLeft = false;
                    IsRight = true;
                }
                else{
                    IsLeft = true;
                    IsRight = false;
                }
            }
        }
    }
    
    public synchronized void increment(){
	double dt;
	double dwt;
	dwt = 2.0*Math.PI/NPointsT;
	dt = (total_length*wavelength/NPointsZ)/phase_velocity;
	
        CurrentTime += DeltaT;
        TotalTime +=DeltaT;
        
	if(CurrentTime > NPointsT){CurrentTime -= NPointsT; }
	//wt = (angular_frequency)*CurrentTime*dt;
	wt = CurrentTime*dwt;
	current_z++;
	if(current_z >= NPointsZ){current_z=0;}
    }
    
    public synchronized void scan_wave(){
	double z, dz;
	dz = total_length*wavelength/(NPointsZ-1);
	for(int i = 0 ; i < NPointsZ; i++){
	    z = i * dz;
	    x[i] = z;
	    
	    efield[i] =   getExAt(z,wt);
	    hfield[i] =   getHyAt(z,wt);
	 
	}
    }
    
    public double getExAt(double z, double wt){
	return Ex*Exref*Math.exp(-alpha*z)*Math.cos(wt-beta*z+Phix);
	//return Ex*Math.exp(-alpha*z)*Math.cos(wt+Phix);
    }
    
    public double getExMax(double z){
	return Ex*Exref*Math.exp(-alpha*z);
    }
    
    public double getHyAt(double z, double wt){
	//return Ey*Exref*Math.exp(-alpha*z)*Math.cos(wt-beta*z+Phix+Phase-wave_impedance_phase);
        return Ey*Exref*Math.exp(-alpha*z)*Math.cos(wt-beta*z+Phix+Phase-wave_impedance_phase)/wave_impedance_mag_0;
	
    } 
    
}