using System;
using System.Configuration;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Data.OleDb;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.IO;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Net;
using Geom;

namespace GenericImgCutout
{
	/// <summary>
	/// The Survey class was created in order to functionally divide
	/// the SDSSSpecific details from the non-SDSS Specific details.
	/// Survey Class acts like a base class from which are derived
	/// 2 classes viz. SDSSSurvey and NonSDSSSurvey. 
	/// 
	/// The survey class defines the common data variable and has some
	/// abstract method declaration which need to be implemented in the
	/// derived classes. Certain common functionality is kept in this 
	/// class so that it doesnt have to be implemented again in each
	/// derived class.
	/// </summary>
	
	public abstract class Survey
	{
		//-------------------------------------		
		// Limits of the input parameters
		//-------------------------------------
		protected const int		max_zoom	=       7;		
		protected const int		max_width	=    2048;
		protected const int		max_height	=    2048;
		protected const int		min_width	=      64;
		protected const int		min_height	=      64;
		protected const double	max_scale	=    60.0;
		protected const double	min_scale	=   0.015;


		//-------------------------------------
		// Input parameters
		//-------------------------------------
		protected double	ra, dec;				// normalized [ra,dec]
		protected Int32	width, height;			// image size
		protected double  scale;					// arcseconds/pixel

		//-------------------------------------
		// Derived parameters
		//-------------------------------------
		// zoom: the image pyramid level [0..max_zoom]
		// imageScale: the additional scaling of 
		// the image beyond walking the pyramid
		//-------------------------------------
		protected int		zoom;					// zoom level 
		protected double	ppd;					// pixels per degree
		protected double	imageScale;				// scale of the image
		protected float	    zoomScale;				// reference scale
		protected float	    size;					// size of the symbols drawn
		protected double	radius, fradius;        // radius for field searches
		protected Hashtable xTable;     	    	// array of astrometry transformation storing transforms for SDSS and non-sdss

		//-------------------------------------
		// Debug support
		//-------------------------------------
		protected StringBuilder dbgMsg = new StringBuilder();	
		protected StringBuilder errMsg = new StringBuilder();	
		protected bool debug			 = false;

		//-------------------------------------
		// region drawing support
		//-------------------------------------
		protected bool   drawRegionlist	= false;
		protected string regionList		= "";
		protected string regionTypes    = "";
		protected string viewPort;
		protected Array   ridlist;

		//-------------------------------------
		// Drawing options
		//-------------------------------------
		protected bool 
			drawList		= false,
			drawPhotoObjs	= false,
			drawSpecObjs	= false, 
			drawTargetObjs	= false, 
			drawGrid		= false,  
			drawLabel		= false, 
			drawOutline		= false, 
			drawBoundingBox = false, 
			drawField		= false, 
			drawMask		= false,
			drawPlate		= false, 
			invertImage		= false,
			drawRegion		= false,
			drawFrames		= true,
			drawQuery	    = false,
			drawRuler       = false;

		//-------------------------------------
		// Graphics canvas
		//-------------------------------------
		protected Canvas canvas				= null;
		//-------------------------------------

		//-------------------------------------
		// DataBase properties
		//-------------------------------------
		protected string		  sConnect	= null;
		protected SqlConnection SqlConn	= null;
		protected SqlDataReader reader	= null;

		protected string surveyName = "";

        // Method declarations.
        // Both SDSS and NonSDSSSurvey should have these implementations.
		public abstract byte[] GetJpeg 
			(double	ra_,						// right ascension in J2000 degrees
			double	dec_, 						// declination in J2000 degrees
			double	scale_,						// arcsec/pixel (0.3961267 is native 1:1 for SDSS)
			Int32	width_,						// image width  (in pixels)
			Int32	height_,					// image height (in pixels)
			string	opt_,						// drawing options
			string	rid_,						// list of regionIDs
			string query_						// Mark objects by using query tool
			);
		public abstract void getFrames ();
		public abstract void getFields ();
		public abstract void getObjects ();


		/// <summary>
		/// getLabel. Display the standard label on the image.
		/// </summary>
		public void getLabel()
		{
			string zoomRatio =  (zoom >= 1)? ("1:"+(int)(Math.Pow(2.0,zoom)+0.01)) : ((int)(imageScale+.5)+":1");
			string theLabel = String.Format(surveyName +"\nra: {0:F5} dec: {1:F5}\npixels per degree: {2:F2}\n"
				+ "image zoom: " + zoomRatio, ra, dec, ppd );		
			canvas.drawLabel(theLabel);
		}

		///<summary>
		/// validateInput. Validate the range limits the input parameters.
		///</summary>		
		public void validateInput(double ra_, double dec_,	double scale_, 
			int height_, int width_, string opt_, string rid_, string query_)
		{
			//----------------------
			// Normalize ra and dec
			//----------------------
			ra	= ra_;
			dec	= dec_;

			dec = dec % 180;					// bring dec within the circle
			if (Math.Abs(dec) > 90)				// if it is "over the pole",
			{										
				dec = (dec - 90) % 180;			// bring int back to the [-90..90] range
				ra  += 180;						// and go 1/2 way round the globe
			}				 
			ra  = ra  % 360;					// bring ra into [0..360]
			if (ra < 0) ra += 360;		

			//----------------------------
			// clip height, width and ppd
			//----------------------------
			height	= Math.Max(min_height, Math.Min(max_height, height_));
			width	= Math.Max(min_width,  Math.Min(max_width, width_));
			scale	= Math.Max(min_scale,  Math.Min(max_scale, scale_));

			if (rid_!="") 
			{
				//-----------------------
				// fill the region list
				//-----------------------
				drawRegionlist	= true;
				regionList		= rid_;
				String[] rlist	= rid_.Split(',');

				ridlist = Array.CreateInstance(typeof(Int64),rlist.Length);
				for(int i=0;i<rlist.Length;i++)
				{
					ridlist.SetValue(Convert.ToInt64(rlist[i]),i);
				}
				Array.Sort(ridlist);
			}
			
			// We cannot validate the mark query until the search size is set,
			// but at least we flag that we want to display a query
			if (query_.Length > 0) drawQuery = true; 

			// Set the flags for the various drawing options.
			for (int i = 0; i < opt_.Length; i++)
			{
				char c = opt_[i];
				switch (c) 
				{
					case 'G': drawGrid = true; 
						break;
					case 'L': drawLabel = true; 
						break;
					case 'P': drawPhotoObjs = true; 
						break;
					case 'S': drawSpecObjs = true; 
						break;
					case 'T': drawTargetObjs = true; 
						break;
					case 'B': drawBoundingBox = true; 
						break;
					case 'F': drawField = true; 
						break;
					case 'O': drawOutline = true; 
						break;
					case 'M': drawMask = true; 
						break;
					case 'I': invertImage = true;
						break;
					case 'C': drawFrames = true;
						break;
					case 'Q': drawPlate = true; 
						break;
					case 'R': //Takes this comment out once the interface is ready to accept the ruler option.
						drawRuler = true;
						break;
					case 'H': regionTypes +="'TILE'";
						break;
					case 'U': regionTypes +="'STRIPE'";
						break;
					case 'V': regionTypes +="'STAVE'";
						break;
					case 'K': regionTypes +="'CHUNK'";
						break;
					case 'D': regionTypes +="'PRIMARY'";
						break;
					case 'W': regionTypes +="'WEDGE'";
						break;
					case 'X': regionTypes +="'TILEBOX'";
						break;
					case 'Y': regionTypes +="'SKYBOX'";
						break;
					case 'Z': regionTypes +="'TIGEOM'";
						break;
					case 'A': regionTypes +="'SECTORLET'";
						break;
					case 'E': regionTypes +="'SECTOR'";
						break;
					case 'N': regionTypes +="'SEGMENT'";
						break;
					case 'J': regionTypes +="'CAMCOL'";
						break;

					case '?': debug = true; 
						break;
				}
			}

			// Make sure that the RegionTypes are comma separated
			if (regionTypes!="") 
			{
				regionTypes = regionTypes.Replace("''","','");
				drawRegion = true;
			}
		}

		/// <summary>
		/// Disconnect from Database.
		/// </summary>
		public void disconnectFromDataBase()
		{
			if (reader != null) reader.Close();		// deallocate the SQL connection
			if (SqlConn != null)					// close the SQL connection
			{
				SqlConn.Close();								
				SqlConn.Dispose();	
			}			
		}

		/// <summary>
		/// Connect to Database.
		/// </summary>
		public void connectToDataBase() 
		{
			SqlConn = new SqlConnection(sConnect);			
			try 
			{
				SqlConn.Open();
				if (debug && false) canvas.displayMessage("Connected to the DataBase \n");
			} 
			catch (Exception e)
			{
				StringBuilder msg = new StringBuilder();
				msg.AppendFormat("Cannot connect to Database: {0}, Source Data: {1}\n", 
					SqlConn.Database, SqlConn.DataSource);
				throw new Exception(msg.ToString() + e.Message);
			}
		}	

		/// <summary>
		/// Converts ra into decimal degrees.
		/// </summary>
		public static double hms2deg(String s) 
		{	
			string[] a = s.Split(':');
			double v = 15.0 * Convert.ToDouble(a[0]) + Convert.ToDouble(a[1])/ 4.0 + Convert.ToDouble(a[2]) / 240.0;

			return v;
		}


		/// <summary>
		/// Converts dec into decimal degrees.
		/// </summary>
		public static double dms2deg(String s) 
		{	
			string[] a = s.Split(':');
			double v; 

			if (s.LastIndexOf("-") == 0)
				v = -(-1.0 * Convert.ToDouble(a[0]) + 
					Convert.ToDouble(a[1]) / 60.0   + 
					Convert.ToDouble(a[2]) / 3600.0);
			else
				v = (Convert.ToDouble(a[0])         + 
					Convert.ToDouble(a[1]) / 60.0   + 
					Convert.ToDouble(a[2]) / 3600.0 );
			return v;			
		}

		/// <summary>
		/// Asamble a generic message and throws the Exception
		/// </summary>
		public void showException(string sFunction, string sQuery, Exception e)
		{

			StringBuilder msg = new StringBuilder();
			msg.AppendFormat("{0} has failed:\n{1}\n", sFunction, sQuery);
			msg.AppendFormat("Exception Message:{0}", e.Message);
				
			throw new Exception(msg.ToString()); //Actual exception
		}
	}
}
/* Revision History

        $Log: Survey.cs,v $
        Revision 1.1.1.1  2006/11/14 02:56:29  gupchup
        no message

        Revision 1.1.1.1  2006/04/25 16:07:23  gupchup
        Code base that merges original imgcutout code and WCS frame format imgcutout code

		Revision 1.20 2006/01/24 gupchup
		Created new class that separates the SDSS imgcutout details from the generic (WCS) one.
*/