/*
 * Copyright (c) 2000, 2001 Massachusetts Institute of Technology.
 *
 * This software is being provided by the copyright holders under the GNU
 * General Public License, either version 2 or, at your discretion, any later
 * version. (See the file `LICENSE' in the source distribution.)
 *
 * This software is provided "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. The entire risk as
 * to the quality and performance of the program is with you. See the GNU
 * General Public License for more details.
 *
 * The name and trademarks of copyright holders may NOT be used in 
 * advertising or publicity pertaining to the software without specific, 
 * written prior permission. Title to copyright in this software and any 
 * associated documentation will at all times remain with copyright 
 * holders. See the file CRICKETAUTHORS which should have accompanied 
 * this software for a list of all copyright holders. 
 * 
 * Particular files in this distribution may be derived from previously
 * copyrighted software. This copyright applies only to those changes made by
 * the copyright holders listed in the CRICKETAUTHORS file.
 */

import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
public class BeaconInclude extends Panel implements ActionListener{

	//location (spcce)
	public String location = null;
	//UID of this in the location
	public String id = null;
	// name of the beacon
	public String name = null;
	// password 
	public String passwd = null;

	public boolean ready = false;
	// file to be created
	 String f_name =null;
	//path name of this ??? directory
   String f_path =null;
	//used to seed the random number generator
	private Date date;
	//random number generator
	private Random r;
	//maximum length of location string
	final int maxLength = 80;
	//number of rnadom values generated
	final int randomNo = 100; // This is really odd
	//range of the random number
	private final int range = 100;
	//length of the password
	private final int passLength = 4; //make this 10 later
	InputStream in;
	PrintWriter out;

	//GUI for entering values
   GetValues getValues;
	BeaconInclude(){
		f_name = "beacon.h";
		f_path = getPath();
		init();
	}
	BeaconInclude(String name){
		f_name = name;
		f_path = getPath();
		init();
	}
	BeaconInclude(String name, String path){
		f_name = name;
		f_path = path;
		init();
	}
	// loads the configuration data
	void readConfig(){




	}
	// get the directory (we are in ????)
	String getPath(){
		//find out which directoery we are in
		File file = new File("foo.dat");
		String path =null;
		try {
			path = new String(file.getAbsolutePath());
			int k = path.lastIndexOf("foo.dat");
			path = path.substring(0,k);
		} catch (Exception e){}
		return path;
	} 
	

	private void init(){	
		getValues = new GetValues(this);
		add(getValues);
		date = new Date();
		// seed the random number generator
		r = new Random(date.getTime());
	}

	//generates a random number
	int getRandom(){
		  return(r.nextInt(this.range));
	}
	
	//generate an integer by setting the parity of ch to be even
	int evanParity( char ch){
		int num = Character.getNumericValue(ch);
		int i = 0;
		int j = num;
		for(int k = 0; k< 8; k++){
			if((j&1) == 1){
				i++;
				i%=2; // i is zero for even parity			
			}
				j>>>=1;	
		}
		if( i == 1){	
			num+=128;
		}
		return(num);     					
	}
	
	//generate an integer by setting the paritu of num to be even
 	int evenParity(int num){
		int i =0;
		int j = num;
		for(int k = 0; k< 8; k++){
			if((j&1) == 1){
				i++;
				i%=2; // i is zero for even parity			
			}
				j>>>=1;	
		}
		if( i == 1){	
			num+=128;
		}
		return(num);   
	}

	//generates the block parity of an array of integers
	private int blockParity(int num[]){
		int i = 0;
		for(int j = 0 ; j < num.length ; j++)
			 i ^= num[j]; //generates parity
		return(i);
	}

	public void actionPerformed(ActionEvent e){

	 	Object o = e.getSource();
	 	if(o.equals(getValues.password)){
	  		this.passwd = e.getActionCommand();
			getValues.password.selectAll();
	 	}
	 	if(o.equals(getValues.location)){
	  		this.location = e.getActionCommand();
			getValues.location.selectAll();
	 	}
	 	if(o.equals(getValues.id)){
	  		this.id = e.getActionCommand();
		getValues.id.selectAll();
	}


}
public static void main(String args[]){
	BeaconInclude beacon=null;	
	if(args.length ==0){
			beacon = new BeaconInclude();
		} else if (args.length ==1){
		 	beacon = new BeaconInclude(args[0]);
		} else if (args.length == 2){
		 	beacon = new BeaconInclude(args[0], args[1]);
		} else {
		 	System.out.println("Invalied No. of arguments");
			System.exit(1);
		}
		MyFrame f = new MyFrame("Beacon Include Generator", beacon);
		f.add("Center",beacon);
		f.pack();
		f.show();
		}



  public void generate(){



		char[] location =null;
		int id =0;
		int FIN = 17;

		char[] password =null;
		try{
			FileOutputStream write_file = new FileOutputStream(this.f_name);
		} catch (IOException e){
			System.out.println("Caught exception in opening file");
			System.exit(1);
		}
  	   
		this.name = (this.location); 
		try{
			id = Integer.parseInt(this.id);
		} catch(NumberFormatException e){
		 			System.out.println("please enter a valied number");
					System.exit(1);
		}
		//off set the ID from control chars
		if(id < 0){
			System.out.println("Cannot have a negative number as the ID");
			System.exit(1);
		}

		id+= 32;  //check if this can be lower ????????
		if(id > 127){
		 	System.out.println(" ID should be less than 95");
			System.exit(1);
		}	
		if((this.name == ".") || (this.passwd == null)){
			System.out.println("Either passowrd or name is null"+name +passwd);
			System.exit(1);
		}
		//get the location and password

		location = this.name.toCharArray();
		password =  this.passwd.toCharArray();

		//set the output file
		try{
			this.out = new PrintWriter(new BufferedWriter(new FileWriter(this.f_name)));
		} catch (IOException e){
		 	System.out.println("Exception in asigning output stream");
			System.exit(1);
		}
		this.out.println("//new location info to be transferred to the eeprom");
		this.out.println("unsigned char new_loc["+this.maxLength+"];");
		if(this.name == null){
		 	System.exit(1);
		}
		this.out.println("//password");
		//write the pasword
		this.out.print("eeprom unsigned char passwd["+password.length+"] = {");
		for(int i = 0; i < password.length  ; i++){
			this.out.print("'");
			this.out.print(password[i]);
			this.out.print("'");
  		   if( i == (password.length - 1))
				break;
			this.out.print(',');
		}
		this.out.println("};");

		//current location info (fill the end with 0s to ensure eeprom allocation)
		this.out.println("// current location information");
		this.out.print("eeprom unsigned char cur_loc["+this.maxLength+"]={");
		//now write the contents
		int parity = 0;
		int j;
		int k;
		for(j =0; j < this.maxLength ; j++){

			if(j < location.length){
				k = this.evenParity(location[j]);
				this.out.print(k);	
				parity ^= k;// generate the parity byte here
			} else if (j == location.length){
 		   	k = this.evenParity(FIN);
				this.out.print(k);
				parity ^= k;
			} else if (j == location.length +1){
			  	k =evenParity(id);
				this.out.print(k);
				parity ^= k;

			} else if( j == location.length +2){
				this.out.print(parity);
			} else {
 				this.out.print('0');
			}
			if (j == this.maxLength -1)
				continue;
			this.out.print(',');
			if(j % 40 == 0)
				this.out.print('\n');
		}
		/*
		k = this.evenParity(FIN);
		parity ^=k;
		this.out.print(k);
		this.out.print(',');
		k = this.evenParity(id);
		parity ^=k;
		this.out.print(k);
		this.out.print(',');
		this.out.print(parity);

		j+=3;
		for( ; j < this.maxLength ; j++){
			this.out.print(',');
			this.out.print('0');
		}
		*/
		this.out.println("};");
		//write the valied legth of current location info
		this.out.println("//valied length of current location info");
      this.out.println("eeprom unsigned char cur_length ="+(location.length+3)+";");
    
		 //allocate variable for new locatio lengthinfo
		this.out.println("//valied length of new location info");
      this.out.println("unsigned char new_length = 0;");
    
		//number of random numbers in the array
		this.out.println("#define RAN_COUNT " + this.randomNo);

		//write the array of random numbers
		this.out.println("//array holding the random numbers");
		this.out.print("flash unsigned char random["+this.randomNo+"] ={");
		for(int i =0; i < this.randomNo ; i++){
			this.out.print(this.getRandom());
			if(i == (this.randomNo - 1))
 		   	continue;
			this.out.print(',');
			if(i%40 == 0){
				this.out.print('\n');
			}
		}
		this.out.println("};");

		this.out.close();
	}



	public boolean handleEvent(Event e){
		if(e.id == Event.WINDOW_DESTROY) {
		System.out.println("getting there");
		}
		return super.handleEvent(e);
	}

} 
// GUI for enterring values
class GetValues extends Panel {
	TextField location;
	TextField id;
	TextField password;
	TextField timeRange;
	BeaconInclude include;

	GetValues(BeaconInclude myInclude){
		GridBagConstraints c = new GridBagConstraints();
		GridBagLayout gridbag = new GridBagLayout();
		setLayout(gridbag);
		include = myInclude;

		c.fill = GridBagConstraints.HORIZONTAL;

		Label label1 = new Label("Location", Label.CENTER);
		c.weightx = 1.0;
		c.gridwidth = GridBagConstraints.REMAINDER;
		gridbag.setConstraints(label1, c);
		add(label1);

		location = new TextField("xxxxxxxx", 40);
		c.weightx = 1.0;
		c.gridwidth = GridBagConstraints.REMAINDER;
		gridbag.setConstraints(location,c);
		location.addActionListener(include);
		add(location);

		Label label2 = new Label("ID", Label.CENTER);
		c.gridwidth = GridBagConstraints.REMAINDER;
		gridbag.setConstraints(label2, c);
		add(label2);

		id = new TextField("xxxxxxxx", 40);
		c.weightx = 1.0;
		c.gridwidth = GridBagConstraints.REMAINDER;
		gridbag.setConstraints(id,c);
		id.addActionListener(include);
		add(id);

		Label label3 = new Label("Password", Label.CENTER);
		c.gridwidth = GridBagConstraints.REMAINDER;
		gridbag.setConstraints(label3, c);
		add(label3);

		password = new TextField("xxxxxxxx", 40);
		c.weightx = 1.0;
		c.gridwidth = GridBagConstraints.REMAINDER;
		gridbag.setConstraints(password,c);
		password.addActionListener(include);
		add(password);
	}

	public boolean action(Event e, Object arg){
		if(e.target instanceof TextField){
			//System.out.println("Got it");
			//System.out.println(e.paramString());
			return true;
		}
			return false;
	}

	public void paint(Graphics g){
		Dimension d = size();
		g.drawRect(0,0, d.width-1, d.height -1);
	}
	
	public Insets insets(){
	 	return new Insets(5,5,5,5);
	}
}


class MyFrame extends Frame {
	private BeaconInclude include;

	MyFrame(String title,BeaconInclude included) {
	super(title);
	include =  included ;
		
	}

	public boolean handleEvent(Event e){
		if(e.id == Event.WINDOW_DESTROY) {
		include.generate();
		System.exit(0);
		}
		return super.handleEvent(e);
	}
}





