<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Color Magnitude Diagram">
    <Require feature="locked-domain" />  
    <Require feature="dynamic-height"/>
    <Require feature="opensocial-0.8"/> 
    <Require feature="minimessage"/>

</ModulePrefs>
<Content type="html"><![CDATA[

<!-- chart dependencies -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
<script src="http://sky.astro.washington.edu/gadgets/highcharts/highcharts.js" type="text/javascript"></script>

<div id="divSelections" style="width: 100%;">
    <table> 
    <TBODY>
        <TR>
            <td>
 	           <input id="btDoHR" onclick="hr.plotHR();" type="button" value="Plot Color Magnitude"/>
            </td> 
			<td>
			   <img id="imgSpinner" src="images/spinnerGrey.gif" style="display:none" />
			</td>
			<td>
				<div id="divStatusText"></div> 
			</td>
        </TR> 
    </TBODY>
    </table>
</div>
<div id="divChart1">
</div>

<script src="http://sky.astro.washington.edu/gadgets/js/gDataInterface.js" type="text/javascript"></script>
<script src="http://sky.astro.washington.edu/gadgets/js/astroObjectLib.js" type="text/javascript"></script>



<script type="text/javascript">
    

// Plot (hr) object is global
var hr = null,
    debug = true;

// Writes to the console if debug (global) is true  
function debugLog(msg){
    if ((debug === true) && (window.console && console.log)) { 
         console.log(GADGET_NAME + ": " + msg);
    }
    return;
}



// GLOBAL CONSTANTS
var GADGET_NAME = "Color_Magnitude" + "_" + Math.floor(Math.random()*100000+1).toString();
var chart1; // globally available

// Writes to the console if debug (global) is true  
function debugLog(msg){
    if ((debug === true) && (window.console && console.log)) {
        console.log(GADGET_NAME + ": " + msg);
    }
    return;
}


// create HR object
function init(){
    hr = new Plotter();
	gadgets.window.adjustHeight();
}


function Plotter(){
    var my = new Object();
    // CONSTANTS
    var DEFAULT_NAMESPACE = "NS1",
        MM_TIMER_DURATION = 4,
		PLOT_HEIGHT = 400,
		PLOT_WIDTH = 300;
		
    // PRIVATE
    var _namespaceList = [ DEFAULT_NAMESPACE ];      // list of our current Namespaces. Just init with the default
    
    // Private Helper Variables
    var di = new gDataInterface(GADGET_NAME, DEFAULT_NAMESPACE); // make dataInterface object, init with default
    var miniMsg = new gadgets.MiniMessage();// make MiniMessage object

    // INIT
    var msg = miniMsg.createStaticMessage("Attempting to register gadget...");
    di.registerMe( { gadgetName : GADGET_NAME,
                    namespaceList : _namespaceList,
                    variableList : [ "VP_Coord", "Active_Point_List", "VP_Point_List" ],
                    triggerList : [],
                    successCallback : registrationSuccess,
                    failureCallback : registrationFailure
                } );
 
	
	// Callback after successful registration
    function registrationSuccess(){
        debugLog('Registration successful');
        if (msg) {
            miniMsg.dismissMessage(msg);
            // free up msg
            msg = null;
            miniMsg.createTimerMessage("Registration Succesful.", MM_TIMER_DURATION);
        }
    }
    // Callback after a failure of registration
    // displays message showing failure
    function registrationFailure(){
        debugLog('Registration FAILED!');
        miniMsg.dismissMessage(msg);
        miniMsg.createDismissibleMessage("Unable to register gadget.\nWe cannot communicate with other gadgets.");
    }
    
	// PUBLIC METHODS  
	my.plotHR = function() {
        // TODO: other ways to choose the bounds we want on the gadget
		showSpinner(true, "Getting objects..."); 
		
		// disappear the chart
		showVisualization(false);
		
		// get current VP bounds
        // bounds is array of CelestialCoordinates: [topLeft, bottomRight]
        var bounds = di.readVariable(DEFAULT_NAMESPACE, "VP_Current_Bounds");
        if (bounds === null){
            alert('Set bounds');
			showSpinner(false, "");
            return;
        }
        
		
		// get objects within bounds from catalogue
		
		// multiply ra by 15 to convert to degrees
		// TODO: option for other catalogues
		var maxObjs = 500;
        var sdssQueryData = {cmd: "SELECT TOP " + maxObjs + " objid,modelMag_g,modelMag_r,modelMag_i,ra,dec FROM PhotoPrimary WHERE ra BETWEEN " + 
				bounds[0].getRa() * 15 + " AND " + 
				bounds[1].getRa() * 15 + " AND dec BETWEEN " + 
				bounds[1].getDec() + " AND " + bounds[0].getDec() +
				" AND modelMag_g > -9999" +
				" ORDER BY modelMag_g ASC",
            format: "xml" };
        
      	url = 'http://cas.sdss.org/public/en/tools/search/x_sql.asp';
		makeGETRequest(url, sdssQueryData, sdssResponseCB);
	}
    
    function makeGETRequest(url, data, callback) {
        var params = {};
        getdata = gadgets.io.encodeValues(data);
        params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;
        url = url + '?' + getdata;
        gadgets.io.makeRequest(url, callback, params); 
    }
    
	function sdssResponseCB(obj) {
		// parse the XML
        if (obj.errors.length > 0){
            // errors
            debugLog(obj.errors);
            showSpinner(false, 'Service: ' + obj.errors);
            return;
        }
        else if (obj.text === ""){
            // returned empty string
            showSpinner(false, 'Service returned empty string');
            return;
        }
        xmlDoc = xmlStringToDoc(obj.text);
        // walk XML to create points and write to objectData
        // TODO: make objectData with tree widget
        var objDataText = [];
        var pointsList = [];

        var rows = xmlDoc.getElementsByTagName('Row');
        if (rows.length === 0){
            // no rows
            showSpinner(false, 'No Objects');
        }
        else if ((rows.length === 1) && (rows[0].textContent.indexOf('No rows returned') !== -1)){
            // the special case answer is that no rows were returned
            showSpinner(false, 'No Objects');
            return;
    	}
        // We probably have valid data at this point, so parse it and display it
            
        // Write total # rows to the gadget display
        objDataText.push("<b>Total Objects: " + rows.length + "</b></br>");
        for (var i=0,len=rows.length; i<len; i++){
			var row = rows[i];
            var cc = new UW.astro.CelestialCoordinate(0,0);
			var cObj = new UW.astro.CelestialObject();
            // loop through attributes
            for (var k=0, kLen=row.attributes.length; k<kLen; k++){
                // k is the attribute index
                var attName = row.attributes[k].nodeName;
                var attValue = row.attributes[k].nodeValue;
                
                cc.appendDescription('<b>' + attName + "</b>: " + attValue + "</br>");
				// TODO: make an SDSS Data table inside the description 
                // set all the cc properties
                switch(attName){
                    case "ra":
                        // divide ra by 15 to convert to hours
                        cc.setRa(attValue /15);
						break;
                    case "dec":
                        cc.setDec(attValue);
						break;
					case "modelMag_g":
						cObj.setGMag(attValue);
						break;
					case "modelMag_r":
						cObj.setRMag(attValue);
						break;
                }
                
                // add text for gadget display
                objDataText.push(attName + ": " + attValue + "</br>");
            }
			cObj.setCelestialCoord(cc);
            // add point to the list
            pointsList.push(cObj);
        }
		// write the points to the scatter plot
		plotPointsList(pointsList);
				
        // write the points to the public point list
        var pubList = di.readVariable(DEFAULT_NAMESPACE, "VP_Point_List");
        // TODO: test for the UniqIDList type
        if (pubList === null){
            pubList = new UW.astro.UniqIdList();
        }
        for (var i=0, len=pointsList.length; i<len; i++){
            pubList.append(pointsList[i].getCelestialCoord());
        }

        di.writeVariable(DEFAULT_NAMESPACE, "VP_Point_List", pubList);

		showSpinner(false, "");

		
	}
	
	// plots the g-r vs. g on the color-magnitude diagram
	// @param pList: is an array of celestial coordinates 
	//				 with g and r as properties
	function plotPointsList(pList) {
		var graphData = [];
		
		for (var i=0, len=pList.length; i<len; i++) {
			var cObj = pList[i];
			var g = Math.round(cObj.getGMag() * 10000000) / 10000000;	// round to 7 decimal places
			var r = Math.round(cObj.getRMag() * 10000000) / 10000000;	// round to 7 decimal places
			if ((g !== null) && (r !== null)) {
				var g_r = Math.round((g-r) * 10000000) / 10000000;	
				// only display -1 < g-r < 3 
				if ((g_r >= -1) && (g_r <= 3)) {
					graphData.push( [g_r, r] )
				}
			}
		}

		$(document).ready(function() {
			chart1 = new Highcharts.Chart({
				chart: {
					renderTo: 'divChart1',
					defaultSeriesType: 'scatter'
				},
				title: {
					text: 'Color Magnitude'
				},
				xAxis: {
					title: {
						 enabled: true,
						 text: 'g - r'
					},
					startOnTick: true,
					endOnTick: true,
					showLastLabel: true
				},
				yAxis: {
					title: {
						text: 'r'
					},
					reversed: true
				},
				series: [{
					name: 'Set 1',
					data: graphData
				}] 
			  });
		});	
        
	debugger;
		document.getElementById('divChart1').style.height = PLOT_HEIGHT + "px";
		
		showVisualization(true);
		
	}	


	// HELPER
	function showVisualization(show) {
		if (show) {
			document.getElementById('divChart1').style.display = "block";
		}
		else {
			document.getElementById('divChart1').style.display = "hidden";
		}
		gadgets.window.adjustHeight();
	}

	function showSpinner(show, text){
        // set text status
		document.getElementById('divStatusText').innerHTML = text;
		if (show){
            document.getElementById('imgSpinner').style.visibility = 'block';
        }
        else{
            document.getElementById('imgSpinner').style.visibility = 'hidden';
        }
    }
	
	function xmlStringToDoc(text){
        if (window.DOMParser){
            parser=new DOMParser();
            xmlDoc=parser.parseFromString(text,"text/xml");
        }
        else // Internet Explorer
        {
            xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async="false";
            xmlDoc.loadXML(text); 
        } 
        // TODO: test to verify its created
        return xmlDoc;
    }
    


    return my;
}


    gadgets.util.registerOnLoadHandler(init); 


</script>
  
  ]]>
 </Content>
</Module>
