//Modle program: namespace is TrackingController. It will be used by both server and client
//define Controller class,
//distribute object Position, TrackeeServant, TrackeeManagerservant 
// ----------------------------------------------------------------

using System;
using System.IO;
using System.Drawing;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Channels;

// The .Net remoting with Tcp channel is just like DCOM, it is suitable for Lan
// it is faster then using the Http
// if the remoting system need to access the firewall, use the Http channel
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Serialization;

using System.Collections;
using System.Windows.Forms;         //for MessageBox


namespace TrackingController
{
	//Controller class
    //-----------------------------
	public class Controller
	{
		private ArrayList m_trackees;               //store all trcakeeservanrs
		private ArrayList m_views;                  //store all mapViews
		private string m_channelType;               //.Net remoting channel type(tcp ot http)
		private int m_port;                         //.Net remoting port number
		private string m_workDirectory;             // default work directory   
		//private Position m_currentTrackerPosition = null;
		private TrackeeServant m_currentTracker = null;

		//constructor
		public Controller()
		{
			m_views=new ArrayList();
			m_trackees=new ArrayList();
			m_port=4000;
			m_channelType="TCP";
		}
		
		//declaring View property
		public ArrayList Views
		{
			set	{	m_views=value;	}
			get	{	return m_views;	}
		}

		//declaring Trackees property
		public ArrayList Trackees
		{
			set	{	m_trackees=value;	}
			get	{	return m_trackees;	}
		}
		//declaring ChannelType property
		public string ChannelType
		{
			set	{	m_channelType = value;	}
			get	{	return m_channelType;	}
		}
		//declaring Port property
		public int Port
		{
			set	{	m_port=value;	}
			get	{	return m_port;	}
		}
		//declaring Port property
		public string WorkDir
		{
			set	{	m_workDirectory=value;	}
			get	{	return m_workDirectory;	}
		}
		/*public Position CurrentTrackerPosition
		{
			set	{	m_currentTrackerPosition=value;	}
			get	{	return m_currentTrackerPosition;	}
		}*/
		public TrackeeServant CurrentTracker
		{
			set	{	m_currentTracker=value;	}
			get	{	return m_currentTracker;	}
		}


        //if controller update, then refresh the view
		public void update()
		{
			for (int i=0; i< this.Views.Count; i++)
			{
				System.Windows.Forms.Form aView = (System.Windows.Forms.Form)this.Views[i];
				aView.Refresh();
			}
		}
	}


    /************************************************************************************
	// Position class
	// --------
	// Position will be passing by remoting object value,  so it must be Serializable!!
	// Geographical position of a trackee as latitude(90 to -90) and longitude(-180 to 180)
	// in Degrees. 
	// Serializable the class for passing the object by value
	// 2004.10.29 add StringToObject method,  
	
	**************************************************************************************/
	[Serializable]
	public class Position
	 {
		private double latitude;
		private double longitude;

		// Constructor
		public Position(double lat, double lon)
		{
			latitude = lat;
			longitude = lon;
		}

	
		//Declaring Latitude Property 
		public double Latitude 
		{
			get {	return latitude; 	}
			set {	latitude = value; 	}
		}

		//Declaring Longitude Property 
		public double Longitude 
		{
			get {	return longitude; 	}
			set {	longitude = value; 	}
		}

		
		// convert this geographical coordinate (latitude and longitude in degrees) to screen coordinate(X, Y)
		public Point ToPoint(double dScaleX,double dScaleY,double dLatOffset, double dLonOffset)  
		{
			// Position is stored in the "x" and "y" variables
			int x = ((int)((this.Longitude-dLonOffset)*dScaleX + 0.5));
			int y = ((int)((dLatOffset-this.Latitude)*dScaleY + 0.5));
			// Create and return a point
			return new Point(x, y);
		}
		
		//get the degree, ' and " of the position
		public int LonDegree()
		{
			return (int) Math.Abs(longitude);
		}
		public int LonMin()
		{
			return (int)(( Math.Abs(longitude) - (double)((int) Math.Abs(longitude) ))*60);
		}
		public int LonSec()
		{
			return (int)( Math.Abs(longitude)*3600 - (double)( LonDegree()*3600+LonMin()*60) + 0.5);
		}

		//longitude >0 is East "E", <0 is West "W"
		public string LonState()
		{
			if ( longitude > 0 )
				return "E";
			else
				return "W";
		}
		
		public int LatDegree()
		{
			return (int) Math.Abs(latitude);
		}
		public int LatMin()
		{
			return (int)((Math.Abs(latitude)-(double)( (int)Math.Abs(latitude) ))*60);
		}
		public int LatSec()
		{
			return (int)( Math.Abs(latitude)*3600 - (double)(LatDegree()*3600+LatMin()*60) + 0.5);
		}

		//above the equator, lat>0 below equator, lat<0
		public string LatState() 
		{
			if ( latitude > 0 )
				return "N";
			else
				return "S";
		}

		public string LonString()
		{
			string temp = "Lon "+Convert.ToString(LonDegree())+" ";
			if (LonMin()>0)
				temp+=Convert.ToString(LonMin())+@"' ";
			else
				temp+=@"00'";
			
			if (LonSec()>0)
				temp+=Convert.ToString(LonSec())+@""" ";
			else
				temp+=@"00"" ";

			temp+= LonState();
			return temp;
		}
		public string LatString()
		{
			string temp = "Lat "+Convert.ToString(LatDegree())+" ";
			if (LatMin()>0)
				temp+=Convert.ToString(LatMin())+@"' ";
			else
				temp+=@"00'";
			
			if (LatSec()>0)
				temp+=Convert.ToString(LatSec())+@""" ";
			else
				temp+=@"00"" ";

			temp+= LatState();
			return temp;
		}

		public static Position StringToObject(String latStr,String lonStr)
		{
			double lat,lon;
			string latStr1,lonStr1;

			latStr1 = latStr.Substring(7,1);
			lonStr1 = lonStr.Substring(8,1);

			if (latStr == null || lonStr ==null ||
				(latStr1!="N" && latStr1!="S" && latStr1!="'" &&  latStr1!=",")
				||(lonStr1!="E" && lonStr1!="W" && lonStr1!="(" &&  lonStr1!=")"))
				return null;
	
			try
			{
				lat = Convert.ToDouble(latStr.Substring(0,2))+Convert.ToDouble(latStr.Substring(2,5))/60; 
				lon = Convert.ToDouble(lonStr.Substring(0,3))+Convert.ToDouble(lonStr.Substring(3,5))/60; 
			}
			catch(Exception e ) 
			{
				string temp = e.ToString();
				return null;
			}	
			
			if (lat>90 || lat <0 || lon>180 || lon <0)
				return null;

			if (latStr1 == "S" || latStr1 == ",") //"lat range:  90 to-90: N-S"
				lat = - lat; 
			
			if (lonStr1 == "W" || lonStr1 == ")") //longitude range:-180~ 180 (W ~ E)
				lon = - lon;
			return new Position(lat,lon);
			}
	} //Position class end



	/******************************************************************************************
	// TrackeeServant
	// --------------
	// Making TrackeeServant Remotable: TrackeeServant extends from MarshalByRefObject Class
	********************************************************************************************/
	public class TrackeeServant: MarshalByRefObject
	{
		//Attributes
		protected string  m_id;				         //Tracker ID
		protected Color  m_color;				     //Tracker Color
		protected Position m_position=null;				 //the current position
		protected Controller m_controller;					 //a view that shows a map and trcakees
		protected string m_label=null;               //tracker label
		protected Font m_font = null;				 //label font
		protected Color m_labelColor;                //label Colort
		protected static long numOfTrackee=100000;   //for creating trackee identity

		//constructor
		public	TrackeeServant(Position aPosition, Color aColor, Controller aController)
		{
			m_id = Convert.ToString(numOfTrackee);
			m_position = aPosition;           // Position of the trackee
			m_color = aColor;                 // Color of this trackee
			m_controller = aController;
			m_label = Convert.ToString(numOfTrackee);
			m_labelColor = Color.Black;
			m_font = new Font("Arial", 7.0f);
		}

		// Constructor (1 parameters)   Defines color
		public TrackeeServant(Color aColor, Controller aController)
		{
			m_id = Convert.ToString(numOfTrackee);
			m_color = aColor;
			m_controller=aController;
			m_label = Convert.ToString(numOfTrackee);
			m_labelColor = Color.Black;
			m_font = new Font("Arial", 7.0f);
		}

		public void delete()
		{
			//unregisters the trackee objects from publication 
			RemotingServices.Disconnect(this);
			//delete the tracker from the Controller
			Controller.Trackees.Remove(this);
			Controller.update();
		}
        
		public string ID 
		{
			get {	return m_id;		}
			set {	m_id = value; 		}
		}
		//Declaring position Property 
		public Position Position 
		{
			get {	return m_position; 	}
			set {	m_position = value; }
		}
   		//Declaring color Property 
		public Color Color 
		{
			get {	return m_color; 	}
			set {	m_color = value; 	}
		}
		//Declaring Controller Property 
		public Controller Controller 
		{
			get {	return m_controller; 	}
			set {	m_controller = value; 	}
		}
		public string Label 
		{
			get {	return m_label; 	}
			set {	m_label = value; 	}
		}
		public Font Font 
		{
			get {	return m_font;	 	}
			set {	m_font = value; 	}
		}
		public Color LabelColor 
		{
			get {	return m_labelColor;	}
			set {	m_labelColor = value;	}
		}

		//remoting method: Set the current position
		public void setPosition(double lat,double lon)//Position pos)
		{
			//set the new position
			this.Position = new Position(lat,lon);
			//this.Controller.CurrentTrackerPosition = Position;
			this.Controller.CurrentTracker = this;
			//append to the callsign file 
			StreamWriter fs = File.AppendText(this.m_controller.WorkDir+"\\profile\\"+this.ID+".dat");
			fs.WriteLine(this.ID+"	"+DateTime.Now.ToString()+": "+ this.Position.Latitude+" "+this.Position.Longitude);
			fs.Close();

			this.Controller.update();
		}

		//remoting method: Set the current position, pass the position object
		public void setPosition(Position pos)
		{
			//set the new position
			this.Position = pos;
			this.Controller.CurrentTracker = this ;// Position = Position;
			//append to the callsign file 
			StreamWriter fs = File.AppendText(this.ID+".dat");
			fs.WriteLine(this.ID+"	"+this.Position.Latitude+" "+this.Position.Longitude);
			fs.Close();
					
			this.Controller.update();
		}

		public static string getTrackeeIndentity()
		{
			string trackeeIndentity;
			trackeeIndentity = "Trackee"+numOfTrackee;
			numOfTrackee++;
			return trackeeIndentity;
		}

	} //trackeeServant class end


    

    /********************************************************************/
	//TrackeeManager: clients use TrackeeManager to create new trackees
	//-----------------------------------------------------------------
	public class TrackeeManagerServant: MarshalByRefObject
	{
		protected Controller m_controller;             //a view that shows a map and trcakees
  

		// Overrides the lease settings for this object.
		//sxt Nov. 5, 2004 set the lifetime.
		public override Object InitializeLifetimeService()
		{
			ILease lease = (ILease)base.InitializeLifetimeService();
			// Normally, the initial lease time would be much longer.
			// It is shortened here for demonstration purposes.
			/*if (lease.CurrentState == LeaseState.Initial)
			{
				lease.InitialLeaseTime = TimeSpan.FromDays(1);//FromMinutes(5);
				lease.SponsorshipTimeout = TimeSpan.FromMinutes(5);
				lease.RenewOnCallTime = TimeSpan.FromDays(1);
			}*/
			return null;//lease;
		}

		public TrackeeManagerServant(Controller aController)
		{
			m_controller = aController;
		}
		
		//declaring the View property
		public Controller Controller
		{
			set	{	m_controller = value; 	}
			get	{	return m_controller;		}
		}

		//remoting method: create a trackee and returen the trackee identity
		public string create()
		{
			try
			{
				// create and publish the trackee remoting object
				// I use the dynamic publish remoting object way to publish the remoting object
				// if use the normal way to register the remoting object,the constructor of the remoting object must be default(no parameter)
				// and I can use the instance of TrackeeServant class in server side
				// The TrackeeServant is public as a remoting object with au unique URI

				//create a Trackeeservant
				TrackeeServant aTrackee = new TrackeeServant(Color.Red,this.Controller);
				//add this trackeeServant to the controller's m_trcakees
				this.Controller.Trackees.Add(aTrackee);
	   
				//create a trackee indentity for this trackee object
				string trackeeIdentity = aTrackee.ID;
              
				//generate the reference of the remoting object.
				ObjRef ref1 = RemotingServices.Marshal(aTrackee,trackeeIdentity);
				
				return trackeeIdentity;
			}
			// Handle exception
			catch(Exception e ) 
			{
				MessageBox.Show(e.ToString());
			}	
            return null;
		} //create method end
		
		//remoting method: create a trackee with a specified ID 
		public void create(string trackerID)
		{
			try
			{
				//create a Trackeeservant
				TrackeeServant aTrackee = new TrackeeServant(Color.Red,this.Controller);
				//set the ID
				aTrackee.ID = trackerID; 
				aTrackee.Label = trackerID;
				//add this trackeeServant to the controller's m_trcakees
				this.Controller.Trackees.Add(aTrackee);
	   
				//generate the reference of the remoting object.
				ObjRef ref1 = RemotingServices.Marshal(aTrackee,trackerID);
			}
			catch(Exception e ) 
			{
				MessageBox.Show(e.ToString());
			}	
		} 

		//remoting method: check whether or not a specified tracker exist 
		public bool isAliveTracker(string trackerID)
		{
			TrackeeServant aTrackee = null;
			for (int i = 0; i <Controller.Trackees.Count; i++)
			{
				if(this.Controller.Trackees[i] != null)
				{
					aTrackee = (TrackeeServant)Controller.Trackees[i];
					if (aTrackee.ID == trackerID)
						return true;
				}
			}
			return false;
		}
		
        //Nov.5 2004 add a method setPosition(string callsign_name, double lat,double lon remoting object TrackeeManager's setPosition() to set the trackee position
        //don't need remoting object TrackeeServant (Don't create Tracker remoting object for each trackee. 
		//add the "callsign class" in the modle.cs  
		public void setPosition(string trackerID,double lat,double lon)
		{
			TrackeeServant aTrackee = null;
			//If is the trackee alive?
			int i ;
			for (i = 0; i <Controller.Trackees.Count; i++)
			{
				if(this.Controller.Trackees[i] != null)
				{
					aTrackee = (TrackeeServant)Controller.Trackees[i];
					if (aTrackee.ID == trackerID)
						break;
				}
			}
			//create trackee
			if (i >=Controller.Trackees.Count)
			{
				//create a trackee
				aTrackee = new TrackeeServant(Color.Red,this.Controller);
				//set the ID
				aTrackee.ID = trackerID; 
				aTrackee.Label = trackerID;
				//add this trackeeServant to the controller's m_trcakees
				this.Controller.Trackees.Add(aTrackee);
			}

			//set position
			aTrackee.setPosition(lat,lon);
		}

	}//TrackeeManager class end


	public class MyColor
	{
		public static Color color(int iColorType)
		{
			Color m_color;
			switch (iColorType)
			{         
				// 0x00 to 0x20 for line's color
				case 0:
					m_color = System.Drawing.Color.DarkGreen;
					break;                  
				case 1:   
					m_color = System.Drawing.Color.Purple;
					break;                  
				case 2:   
					m_color = System.Drawing.Color.DarkGreen;
					break;                  
				case 3:   
					m_color = System.Drawing.Color.Cyan;
					break;                  
				case 4:   
					m_color = System.Drawing.Color.Brown;
					break;                  
				case 5:   
					m_color = System.Drawing.Color.Plum;
					break;                  
				case 6:
					m_color = System.Drawing.Color.Orange;
					break;                  
				case 7:
					m_color = System.Drawing.Color.DarkGray;
					break;                  
				case 8:
					m_color = System.Drawing.Color.Black;
					break;                  
				case 9:
					m_color = System.Drawing.Color.Blue;
					break;                  
				case 10: //0x0a
					m_color = System.Drawing.Color.LightGreen;
					break;                  
				case 11: //0x0b
					m_color = System.Drawing.Color.MediumOrchid; //light purple
					break;                  
				case 12: //0x0c
					m_color = System.Drawing.Color.Red;
					break;                  
				case 13: //0x0d
					m_color = System.Drawing.Color.Magenta;
					break;                  
				case 14:  //0x0e
					m_color = System.Drawing.Color.Yellow;
					break;                  
				case 15: //0x0f
					m_color = System.Drawing.Color.White;
					break;                  
				case 16:  //0x10
				case 17:  //0x11
				case 18:  //0x12
				case 19:  //0x13
					m_color = System.Drawing.Color.Black;
					break;                  
				case 20: //0x14
					m_color = System.Drawing.Color.Silver;
					break;                  
				case 21: //0x15
					m_color = System.Drawing.Color.DeepPink;//.Magenta;
					break;                  
				case 22: //0x16
					m_color = System.Drawing.Color.MediumOrchid; //light purple
					break;                  
				case 23: //0x17
					m_color = System.Drawing.Color.LightBlue;
					break;                  
				case 24: //0x18
					m_color = System.Drawing.Color.Purple;
					break;                  
				case 25: //0x19
					m_color = System.Drawing.Color.SandyBrown; //light orange 
					break;                  
				case 26: //0x1a
					m_color = System.Drawing.Color.SteelBlue;
					break;                  
				case 32: //0x20
					m_color = System.Drawing.Color.White;
					break;   
               
				//filled object color
				case 128: //0x80
				case 129: //0x81
					m_color=Color.LightGray;
					break;
				case 130: //0x82
					m_color=Color.OrangeRed;
					break;
				case 131: //0x83
					m_color=Color.Yellow;
					break;
				case 132: //0x84
					m_color=Color.SpringGreen;
					break;
				case 133: //0x85
					m_color=Color.DodgerBlue;
					break;
				case 134: //0x86
					m_color=Color.Cyan;
					break;
				case 135: //0x86
					m_color=Color.Fuchsia;
					break;
				case 136: //0x88
					m_color=Color.White;
					break;
				case 137: //0x89
					m_color=Color.DarkOrange;
					break;
				case 138: //0x8a
					m_color=Color.Cyan;
					break;
				case 139: //0x8b
					m_color=Color.SandyBrown;
					break;
				case 140://0x8c
					m_color=Color.Fuchsia;
					break;
				case 141://0x8d
					m_color=Color.GreenYellow;
					break;
				case 142://0x8e
					m_color=Color.LightGray;
					break;
				case 143: //0x8f
					m_color=Color.LightYellow;
					break;
							
				default :            
					m_color = System.Drawing.Color.Black;
					break;      
			}
			return m_color;
		}
	}

} //namespace end
