/**
 *
 * @project     CWC2
 * @revision    $Id: cwc_roi.js,v 1.31 2006/03/13 16:44:42 jlacroix Exp $
 * @purpose     The ROI Manager - a group of functions for managing
 * regions of interest and the tools that define them.
 * @author      DM Solutions Group (spencer@dmsolutions.ca)
 * @copyright
 * <b>Copyright (c) 2002, DM Solutions Group Inc.</b>
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
 
 
var CWCIsNav4 = (document.layers) ? 1:0;

var CWCIsIE = (document.all) ? 1:0;
var CWCIsNav6 = (document.getElementById && !document.all) ? 1:0;

if (CWCIsNav4 || CWCIsNav6)
{
    document.captureEvents(Event.MOUSEMOVE);
    document.captureEvents(Event.MOUSEDOWN);
    document.captureEvents(Event.MOUSEUP);
    document.captureEvents(Event.RESIZE);
    document.captureEvents(Event.KEYPRESS);
}

var ROI_MODE_FIRST = 1;
var ROI_MODE_NORMAL = ROI_MODE_FIRST;
var ROI_MODE_ADD = ROI_MODE_NORMAL + 1;
var ROI_MODE_SUBTRACT = ROI_MODE_ADD + 1;
var ROI_MODE_LAST = ROI_MODE_SUBTRACT;

/*
 * ROI Events
 */
var ROI_CHANGED = 0;
 
var goCWCROIManager = new CWCROIManager();

/*
 * The ROI Manager
 */
function CWCROIManager()
{
    this.aROI = new Array();
    this.nActiveROITool = 0;
    this.oForm = null;
    
    this.mode = ROI_MODE_NORMAL;
    this.szRendererURL = "";

    this.geoMinX = null;
    this.geoMinY = null;    
    this.geoMaxX = null;    
    this.geoMaxY = null;
    
    this.pixMinX = null;
    this.pixMinY = null;    
    this.pixMaxX = null;    
    this.pixMaxY = null;
    
    this.szEdgeColor = "#00FF00";
    this.nEdgeWidth = 2;

    this.szFillColor = this.szEdgeColor;
    this.nFillOpacity = 0.5;
    this.bFill = true;

    this.onchange = new Array();
    this.events = new Array();
    this.events[ROI_CHANGED] = new Array();
    
    this.SetFormObject = CWCROIManager_SetFormObject;
    this.Add = CWCROIManager_Add;
    this.Insert = CWCROIManager_Insert;
    this.Redraw = CWCROIManager_Redraw;
    this.GetLast = CWCROIManager_GetLast;
    this.RemoveLast = CWCROIManager_RemoveLast;
    this.RemoveAll = CWCROIManager_RemoveAll;
    this.SetROITool = CWCROIManager_SetROITool;
    this.GetROITool = CWCROIManager_GetROITool;
    this.SetGeoExtents = CWCROIManager_SetGeoExtents;
    this.SetPixelExtents = CWCROIManager_SetPixelExtents;
    this.SetMode = CWCROIManager_SetMode;
    this.SetRendererURL = CWCROIManager_SetRendererURL;
    this.GetRendererURL = CWCROIManager_GetRendererURL;
    this.GetROI = CWCROIManager_GetROI;
    this.Geo2Pix = CWCROIManager_Geo2Pix;
    this.Pix2Geo = CWCROIManager_Pix2Geo;
    this.UpdateLayerVisibility = CWCROIManager_UpdateLayerVisibility;
    this.RegisterEvent = CWCROIManager_RegisterEvent;
    this.DeregisterEvent = CWCROIManager_RegisterEvent;
    this.TriggerEvent = CWCROIManager_TriggerEvent;
}

function CWCROIManager_UpdateLayerVisibility()
{
    if (this.aROI.length > 0)
    {
        //window.status = "show layer";
        CWCDHTML_ShowLayer( gROIRenderer );
    }
    else
        CWCDHTML_HideLayer( gROIRenderer );
}


function CWCROIManager_GetROI()
{
    return aROI;
}

function CWCROIManager_SetRendererURL( szURL )
{
    this.szRendererURL = szURL;
}

function CWCROIManager_GetRendererURL()
{
    var szURL = this.szRendererURL + "&blah=" + Math.random();
    szURL = szURL + "&width=" + (this.pixMaxX - this.pixMinX);
    szURL = szURL + "&height=" + (this.pixMaxY - this.pixMinY);
    return szURL;
}

function CWCROIManager_SetMode( nMode )
{
    if (nMode >= ROI_MODE_FIRST && nMode <= ROI_MODE_LAST)
    {
        this.mode = nMode;    
    }
    
    if (this.oForm.ROI_MODE)
    {
        this.oForm.ROI_MODE.value = this.mode;
    }
}

function CWCROIManager_SetGeoExtents( fMinX, fMinY, fMaxX, fMaxY )
{
    this.geoMinX = parseFloat( fMinX );
    this.geoMinY = parseFloat( fMinY );    
    this.geoMaxX = parseFloat( fMaxX );    
    this.geoMaxY = parseFloat( fMaxY );
}

function CWCROIManager_SetPixelExtents( nMinX, nMinY, nMaxX, nMaxY )
{
    this.pixMinX = parseInt( nMinX );
    this.pixMinY = parseInt( nMinY );    
    this.pixMaxX = parseInt( nMaxX );    
    this.pixMaxY = parseInt( nMaxY );
}

function CWCROIManager_SetFormObject( oObj )
{
    this.oForm = oObj;
}

function CWCROIManager_RegisterEvent( event, szCode )
{
    lastEvent = (this.events[event]).length;
    this.events[ event ][ lastEvent ] = szCode;
    return true;
}

function CWCROIManager_DeregisterEvent( event, szCode )
{
    bFound = false;
    events = this.events[event];
    for( i=0; i<events.length; i++ )
    {
        if (this.events[i] == szCode )
        {
            this.events[i] = "";
            bFound = true;
        }
    }
    return  bFound;
}

function CWCROIManager_TriggerEvent( event )
{
    var i = 0;
    var nEvents = (this.events[ event ]).length;
    for (i=0; i<nEvents; i++)
    {
        szFunction =  this.events[ event ][ i ];
        if (szFunction != "")
        {
            eval(szFunction);
        }
    }
    return true;
}

function CWCROIManager_Add( oROI )
{
    oROI.manager = this;
    oROI.mode = this.mode;

    var szURL = oROI.GetRendererURL();
    if (szURL == false)
    {
        return false;
    }    
    if (this.mode == ROI_MODE_NORMAL)
    {
        this.RemoveAll();
        this.aROI[0] = oROI;
    }
    else 
    {
        this.aROI[this.aROI.length] = oROI;
    }
    if (this.oForm.ROI_MODE)
    {
        var oImage = CWCDHTML_GetImage( "ROIRenderer" );
        oImage.src = szURL;
    }
    
    this.UpdateLayerVisibility();
    this.TriggerEvent( ROI_CHANGED );
}

/**
 *  This function will redraw the ROI's according to current extent and info.
 *  It is used for when things like extent or projection changes in a mapfile.
 **/
function CWCROIManager_Redraw()
{
    var szURL = this.GetRendererURL();
    if (szURL == false)
    {
        return false;
    }    
    var oImage = CWCDHTML_GetImage( "ROIRenderer" );
    oImage.src = szURL;
        
    this.UpdateLayerVisibility();
}

/**
 * utility function to quickly insert an ROI object into the
 * manager, used when reconstituting the objects after a
 * page load.  This function does not do any error checking
 * or validation of indexes.
 *
 * @param oROI an object to insert into the manager
 * @param nIndex the index to insert the object at
 */
function CWCROIManager_Insert( oROI, nIndex )
{
    oROI.manager = this;
    oROI.mode = this.mode;

    this.aROI[nIndex] = oROI;
}


function CWCROIManager_GetLast( )
{
    if (this.aROI.length > 0)
        return this.aROI[this.aROI.length - 1];
    else
        return null;
}

function CWCROIManager_RemoveLast()
{
    var newROI = new Array();
    var i;
    if (this.aROI.length > 0)
    {
        for (i=0; i < this.aROI.length - 1; i++)
        {
            newROI[i] = this.aROI[i];
        }

        this.aROI[this.aROI.length - 1].Hide();
        this.aROI[this.aROI.length - 1] = null;
        this.aROI = newROI;
        this.TriggerEvent( ROI_CHANGED );
    }
    
    if (this.oForm.ROI_MODE)
    {
        var szURL = this.GetRendererURL();
        if (szURL != null)
        {
            szURL = szURL + "&mode=-1";
            var oImage = CWCDHTML_GetImage( "ROIRenderer" );
            oImage.src = szURL;
        }
    }    
    this.UpdateLayerVisibility();
}

function CWCROIManager_RemoveAll()
{
    var i;
    if (this.aROI.length > 0)
    {
        for (i=0; i < this.aROI.length; i++)
        {
            if (this.aROI[i] != null)
                this.aROI[i].Hide();
           this.aROI[i] = null;
        }
        this.TriggerEvent( ROI_CHANGED );
    }
    this.aROI = new Array();
    if (this.oForm.ROI_MODE)
    {
        var szURL = this.GetRendererURL();
        if (szURL != null)
        {
            szURL = szURL + "&mode=-2";
            var oImage = CWCDHTML_GetImage( "ROIRenderer" );
            oImage.src = szURL;
        }
    } 
    this.UpdateLayerVisibility();
}

function CWCROIManager_SetROITool( nTool )
{
    this.nActiveTool = nTool;
    
    if (this.oForm != null)
    {
        if (this.oForm.NAV_CMD != null)
            this.oForm.NAV_CMD.value = "ROI_TOOL";
        if (this.oForm.NAV_SUBMIT != null)
            this.oForm.NAV_SUBMIT.value = "0";
    }
}

function CWCROIManager_GetROITool( )
{
    return this.nActiveTool
}

/****************************************************************************
* Converts from Geographic coordinates to Pixel coordinates. Returns an
* array of 2 elements containing the resulting x and y positions.
*
* @param x : Value should be between inside the map extents
* @param y : Value should be between inside the map extents
*****************************************************************************/
function CWCROIManager_Geo2Pix( x, y )
{
    if (x >= this.geoMinX && x <= this.geoMaxX &&
        y >= this.geoMinY && y <= this.geoMaxY)
    {
        var width = this.pixMaxX - this.pixMinX;
        var height = this.pixMaxY - this.pixMinY;
        
        var dfDeltaMaxGeoX = this.geoMaxX - this.geoMinX;
        var dfDeltaMaxGeoY = this.geoMaxY - this.geoMinY;

        var dfPixX = (width * (x - this.geoMinX))/ dfDeltaMaxGeoX;
        var dfPixY = height - ((height * (y - this.geoMinY))/ dfDeltaMaxGeoY);

        aReturn = new Array(2);
        aReturn[0] = Math.round(dfPixX);
        aReturn[1] = Math.round(dfPixY);

        return aReturn;
    }
    else
        return false;
}


/****************************************************************************
* Converts from Pixel to Geographic coordinates. Returns an
* array of 2 elements containing the resulting x and y positions.
*
* @param x : Value should be between 0 and the map width
* @param y : Value should be between 0 and the map height
*****************************************************************************/
function CWCROIManager_Pix2Geo(x, y)
{
    var width = this.pixMaxX - this.pixMinX;
    var height = this.pixMaxY - this.pixMinY;
    if (x >= 0 && y >= 0)
    {
        
        var x_pct = (x / width);
        var y_pct = (y / height);

        var dfGeoX = this.geoMinX + ( ( this.geoMaxX -  this.geoMinX) * x_pct);
        var dfGeoY = this.geoMaxY - ( (this.geoMaxY -  this.geoMinY) * y_pct);

        var aReturn = new Array(2);
        aReturn[0] = dfGeoX;
        aReturn[1] = dfGeoY;
        return aReturn;
    }
    else
    {
        return false;
    }
}

/*
 * a Feature-based ROI
 */
function CWCFeatureROI(  )
{
    this.type = "feature";
    this.manager = null;
    this.mode = ROI_MODE_NORMAL;
    
    this.edgeColor = "#00FF00";
    this.edgeWidth = 2;

    this.fillColor = this.edgeColor;
    this.fillOpacity = 0.5;
    this.fillLayer = null;
    this.bFill = true;
    
    this.visible = false;
    
    this.szLayer = "";
    this.x = -1;
    this.y = -1;
    this.geoX = null;
    this.geoY = null;
    
    this.Draw = CWCFeatureROI_Draw;
    this.Set = CWCFeatureROI_Set;
    this.Show = CWCFeatureROI_Show;
    this.Hide = CWCFeatureROI_Hide;
    this.GetRendererURL = CWCFeatureROI_GetRendererURL;
    this.GetROI = CWCFeatureROI_GetROI;
    this.Serialize = CWCFeatureROI_Serialize;
    this.CalculateGeoExtents = CWCFeatureROI_CalculateGeoExtents;
}


function CWCFeatureROI_GetROI()
{
    return false;
}

function CWCFeatureROI_Draw()
{
    return false;
}

function CWCFeatureROI_Set( x, y, szLayer )
{
    this.x = x;
    this.y = y;
    this.szLayer = szLayer;
    
    return false;
}

function CWCFeatureROI_Show()
{
    return false;
}

function CWCFeatureROI_Hide()
{
    return false;
}

function CWCFeatureROI_GetRendererURL()
{
    var szSerialized = this.Serialize();
    if (!szSerialized)
    {
        return false;
    }
    var szURL = this.manager.GetRendererURL();
    
    szURL = szURL + "&" + szSerialized;
    return szURL;
}

function CWCFeatureROI_Serialize()
{
    if (!this.CalculateGeoExtents())
    {
        return false;
    }
    if (this.szLayer == "")
    {
        return false;
    }
    var szURL = "type=" + this.type;
    szURL = szURL + "&mode=" + this.mode;
    szURL = szURL + "&coords=" + this.geoX + "," + this.geoY;
    szURL = szURL + "&edgecolor=" + escape(this.edgeColor);
    szURL = szURL + "&edgewidth=" + this.edgeWidth;
    szURL = szURL + "&fillcolor=" + escape(this.fillColor);
    if (CWCIsIE)
    {
        szURL = szURL + "&fillopacity=-1";
    }
    else
    {
        szURL = szURL + "&fillopacity=" + this.fillOpacity;
    }
    szURL = szURL + "&selectedLayer=" + this.szLayer;
    return szURL;
}

function CWCFeatureROI_CalculateGeoExtents()
{
    if (this.manager != null)
    {
        var aGeo = this.manager.Pix2Geo( this.x, this.y );
        this.geoX = aGeo[0];
        this.geoY = aGeo[1];
        return true;
    }
    return false;
}

/*
 * a Rectangular ROI
 */
function CWCRectangleROI(  )
{
    this.type = "rectangle";
    this.manager = null;
    this.mode = ROI_MODE_NORMAL;
    
    this.left = -2;
    this.top = -2;    
    this.right = -2;    
    this.bottom = -2;
    
    this.geoMinX = null;
    this.geoMinY = null;    
    this.geoMaxX = null;    
    this.geoMaxY = null;
   
    this.topLayer = null;
    this.leftLayer = null;
    this.rightLayer = null;
    this.bottomLayer = null;
    this.edgeColor = "#00FF00";
    this.edgeWidth = 2;

    this.fillColor = this.edgeColor;
    this.fillOpacity = 0.5;
    this.fillLayer = null;
    this.bFill = true;
    
    this.visible = false;
    
    this.Draw = CWCRectangleROI_Draw;
    this.Set = CWCRectangleROI_Set;
    this.Show = CWCRectangleROI_Show;
    this.Hide = CWCRectangleROI_Hide;
    this.GetRendererURL = CWCRectangleROI_GetRendererURL;
    this.GetROI = CWCRectangleROI_GetROI;
    this.Serialize = CWCRectangleROI_Serialize;
    this.CalculateGeoExtents = CWCRectangleROI_CalculateGeoExtents;
}

function CWCRectangleROI_CalculateGeoExtents()
{
    if (this.manager != null)
    {
        var aTL = this.manager.Pix2Geo( this.left, this.top );
        var aBR = this.manager.Pix2Geo( this.right, this.bottom );
        if (aTL != false && aBR != false)
        {
            this.geoMinX = Math.min(aTL[0], aBR[0]);
            this.geoMaxX = Math.max(aTL[0], aBR[0]);    
            this.geoMinY = Math.min(aTL[1], aBR[1]);
            this.geoMaxY = Math.max(aTL[1], aBR[1]); 
            
            //alert( this.geoMinX + "," + this.geoMinY + ":" + this.geoMaxX + "," + this.geoMaxY );
            return true;
        }
        else
        {
            this.geoMinX = null;
            this.geoMinY = null;    
            this.geoMaxX = null;    
            this.geoMaxY = null;
            return false;
        }
    }
    else
    {
        return false;
    }
}

function CWCRectangleROI_GetROI()
{
    
}

function CWCRectangleROI_Draw()
{
    if (!this.visible)
        return;
        
    if( this.topLayer == null || this.leftLayer == null ||
        this.rightLayer == null || this.bottomLayer == null)
    {
        this.visible = false;
        return;
    }
        
    CWCDHTML_ClipLayer(this.topLayer, this.left, this.top, this.right, this.top+this.edgeWidth);
    CWCDHTML_ClipLayer(this.leftLayer, this.left, this.top, this.left + this.edgeWidth, this.bottom);
    CWCDHTML_ClipLayer(this.rightLayer, this.right - this.edgeWidth, this.top, this.right, this.bottom);
    CWCDHTML_ClipLayer(this.bottomLayer, this.left, this.bottom - this.edgeWidth, this.right, this.bottom);
    if (this.bFill)
    {
        if (this.fillLayer != null)
        {
            CWCDHTML_ClipLayer(this.fillLayer, this.left+this.edgeWidth, this.top+this.edgeWidth, this.right-this.edgeWidth, this.bottom - this.edgeWidth);
        }
        else
        {
            this.bFill = false; 
        }
    }
}

function CWCRectangleROI_Set( left, top, right, bottom )
{
    this.left = left;
    this.top = top;    
    this.right = right;    
    this.bottom = bottom;
    
    if (this.visible)
    {
        this.Draw();
    }
}

function CWCRectangleROI_Show()
{
    if( this.topLayer == null || this.leftLayer == null ||
        this.rightLayer == null || this.bottomLayer == null)
    {
        this.visible = false;
        return;
    }
    
    this.visible = true;
    
    CWCDHTML_ShowLayer(this.topLayer);
    CWCDHTML_ShowLayer(this.leftLayer);
    CWCDHTML_ShowLayer(this.rightLayer);
    CWCDHTML_ShowLayer(this.bottomLayer);
    
    CWCDHTML_SetLayerBackgroundColor( this.topLayer, this.edgeColor );
    CWCDHTML_SetLayerBackgroundColor( this.leftLayer, this.edgeColor );
    CWCDHTML_SetLayerBackgroundColor( this.rightLayer, this.edgeColor );
    CWCDHTML_SetLayerBackgroundColor( this.bottomLayer, this.edgeColor );
    
    if(this.bFill)
    {
        CWCDHTML_ShowLayer(this.fillLayer);
        CWCDHTML_SetLayerBackgroundColor( this.fillLayer, this.fillColor );
        CWCDHTML_SetLayerOpacity( this.fillLayer, this.fillOpacity );
    
    }   
    this.Draw();
}

function CWCRectangleROI_Hide()
{
    if( this.topLayer == null || this.leftLayer == null ||
        this.rightLayer == null || this.bottomLayer == null)
    {
        this.visible = false;
        return;
    }
    
    this.visible = false;
    
    CWCDHTML_HideLayer(this.topLayer);
    CWCDHTML_HideLayer(this.leftLayer);
    CWCDHTML_HideLayer(this.rightLayer);
    CWCDHTML_HideLayer(this.bottomLayer);
    
    if(this.bFill)
    {
        CWCDHTML_HideLayer(this.fillLayer);
    }
}

function CWCRectangleROI_GetRendererURL()
{
    var szSerialized = this.Serialize();
    if (!szSerialized)
    {
        return false;
    }
    var szURL = this.manager.GetRendererURL();
    
    szURL = szURL + "&" + szSerialized;
    return szURL;
}

function CWCRectangleROI_Serialize()
{
    if (!this.CalculateGeoExtents())
        return false;
    
    var szURL = "type=" + this.type;
    szURL = szURL + "&mode=" + this.mode;
    szURL = szURL + "&coords=" + this.geoMinX + "," + this.geoMinY + "," + this.geoMaxX + "," + this.geoMaxY;
    szURL = szURL + "&edgecolor=" + escape(this.edgeColor);
    szURL = szURL + "&edgewidth=" + this.edgeWidth;
    szURL = szURL + "&fillcolor=" + escape(this.fillColor);
    if (CWCIsIE)
    {
        szURL = szURL + "&fillopacity=-1";
    }
    else
    {
        szURL = szURL + "&fillopacity=" + this.fillOpacity;
    }
    return szURL;
}

/******************************************************************************
 * a Circle ROI
 *****************************************************************************/
function CWCCircleROI( nPoints )
{
    this.type = "circle";
    this.manager = null;
    this.mode = ROI_MODE_NORMAL;
    
    // set the node image widths
    this.centerNodeImageWidth = 7;
    this.nodeImageWidth = 6;
    
    // set the operating limits for this tool
    this.left = -2;
    this.top = -2;    
    this.right = -2;    
    this.bottom = -2;
   
    // define the center and radius properties
    this.centerX = -2;  // in pixels from corner of map
    this.centerY = -2;  // in pixels from corner of map
    this.radius = 0;
    this.geoRadius = 0;
    this.geoX = 0;
    this.geoY = 0; 
    // default the number of layers to create
    this.numPoints = nPoints;
    
    // loop and build layer objects
    for ( var i=1; i<=this.numPoints; i++ )
    {
        eval('this.Layer' + i + ' = null;');
    }
     
    this.edgeColor = "#00FF00";
    this.edgeWidth = 2;

    this.fillColor = this.edgeColor;
    this.fillOpacity = 0.5;
    this.fillLayer = null;
    this.bFill = true;
    
    this.visible = false;
    
    this.Draw = CWCCircleROI_Draw;
    this.Show = CWCCircleROI_Show;
    this.Hide = CWCCircleROI_Hide;
    this.GetRendererURL = CWCCircleROI_GetRendererURL;
    this.GetROI = CWCCircleROI_GetROI;
    this.Serialize = CWCCircleROI_Serialize;
    //this.CalculateGeoExtents = CWCCircleROI_CalculateGeoExtents;
}
/*
function CWCCircleROI_CalculateGeoExtents()
{
    if (this.manager != null)
    {
        var aTL = this.manager.Pix2Geo( this.left, this.top );
        var aBR = this.manager.Pix2Geo( this.right, this.bottom );
        if (aTL != false && aBR != false)
        {
            this.geoMinX = Math.min(aTL[0], aBR[0]);
            this.geoMaxX = Math.max(aTL[0], aBR[0]);    
            this.geoMinY = Math.min(aTL[1], aBR[1]);
            this.geoMaxY = Math.max(aTL[1], aBR[1]); 
            
            //alert( this.geoMinX + "," + this.geoMinY + ":" + this.geoMaxX + "," + this.geoMaxY );
            return true;
        }
        else
        {
            this.geoMinX = null;
            this.geoMinY = null;    
            this.geoMaxX = null;    
            this.geoMaxY = null;
            return false;
        }
    }
    else
    {
        return false;
    }
}
*/
function CWCCircleROI_GetROI()
{
    
}

function CWCCircleROI_Draw()
{
    // init vars
    var dX = 0;
    var dY = 0;

    if (!this.visible)
        return;
        
    // calculate the distance to the mouse and angle interval (rad)
    with (Math)
    {
        var dist = sqrt( pow( gROIToolmouseX - gROICircleToolx1, 2 ) + pow( gROIToolmouseY - gROICircleTooly1, 2 ) );
        var angleInterval = 2 * PI / this.numPoints;
    }

    // set the center and radius
    this.centerX = gROICircleToolx1 - this.left;
    this.centerY = gROICircleTooly1 - this.top;
    this.radius = dist;
    
    // position nodes
    CWCDHTML_SetLayerPos( this.centerLayer, gROICircleToolx1-(this.centerNodeImageWidth/2), gROICircleTooly1-(this.centerNodeImageWidth/2) );

    // loop and position each of the point layers around the circle
    for ( var i=0; i<this.numPoints; i++ )
    {
        // calculate the x and y position (account for image width/height)
        dX = (Math.cos(i*angleInterval) * dist) - (this.nodeImageWidth/2);
        dY = (Math.sin(i*angleInterval) * dist) - (this.nodeImageWidth/2);;
        
        // position the layer
        eval('CWCDHTML_SetLayerPos( this.Layer' + (i+1) + ', gROICircleToolx1 + dX, gROICircleTooly1 + dY );');
        
        // show/hide as necessary
        if ( gROICircleToolx1 + dX < this.left || gROICircleToolx1 + dX > this.right - this.nodeImageWidth || 
             gROICircleTooly1 + dY < this.top || gROICircleTooly1 + dY > this.bottom - this.nodeImageWidth )
        {
            // hide
            eval('CWCDHTML_HideLayer(this.Layer' + (i+1) + ');'); 
        }
        else
        {
            // show
            eval('CWCDHTML_ShowLayer(this.Layer' + (i+1) + ');'); 
        }
    }
}

function CWCCircleROI_Show()
{
    // set flag   
    this.visible = true;
    
    CWCDHTML_ShowLayer(this.centerLayer);
    
    // loop and show layer objects
    for ( var i=1; i<=this.numPoints; i++ )
    {
        eval( 'CWCDHTML_ShowLayer(this.Layer' + i + ');' );
    }
    
    this.Draw();
}

function CWCCircleROI_Hide()
{
    // set flag
    this.visible = false;
    
    // loop and hide layer objects
    for ( var i=1; i<=this.numPoints; i++ )
    {
        eval( 'CWCDHTML_HideLayer(this.Layer' + i + ');' );
    }
    
    CWCDHTML_HideLayer(this.centerLayer);
}

function CWCCircleROI_GetRendererURL()
{
    var szSerialized = this.Serialize();
    if (!szSerialized)
        return false;
        
    var szURL = this.manager.GetRendererURL();
    
    szURL = szURL + "&" + szSerialized;
    return szURL;
}

function CWCCircleROI_Serialize()
{ 
    // init vars
    var aCenter;
    var aRadius;
    var szURL;

    // convert to ground units
    if (this.manager != null)
    {
        aCenter = this.manager.Pix2Geo( this.centerX, this.centerY );
        aRadius = this.manager.Pix2Geo( parseInt(this.centerX) + parseInt(this.radius), this.centerY );
        this.geoRadius = aRadius[0]-aCenter[0];
        this.geoX = aCenter[0];
        this.geoY = aCenter[1];
    }

    szURL = "type=" + this.type;
    szURL = szURL + "&mode=" + this.mode;
    szURL = szURL + "&coords=" + aCenter[0] + ',' +  aCenter[1] + ',' + 
                                                aRadius[0] + ',' + aRadius[1];
    szURL = szURL + "&edgecolor=" + escape(this.edgeColor);
    szURL = szURL + "&edgewidth=" + this.edgeWidth;
    szURL = szURL + "&fillcolor=" + escape(this.fillColor);
    if (CWCIsIE)
    {
        szURL = szURL + "&fillopacity=-1";
    }
    else
    {
        szURL = szURL + "&fillopacity=" + this.fillOpacity;
    }
    return szURL;
}

/******************************************************************************
 * a Polygon ROI
 *****************************************************************************/
function CWCPolygonROI()
{
    this.type = "polygon";
    this.manager = null;
    this.mode = ROI_MODE_NORMAL;
    
    this.edgeColor = "#00FF00";
    this.edgeWidth = 2;

    // set the operating limits for this tool
    this.left = -2;
    this.top = -2;    
    this.right = -2;    
    this.bottom = -2;    
    
    this.fillColor = this.edgeColor;
    this.fillOpacity = 0.5;
    this.fillLayer = null;
    this.bFill = true;
    this.geoCoords = "";   //used to store the nodes in geographic coordinates, as derived in "Serialize()"
    this.aNodeCoords = new Array();
    
    this.visible = false;
    
    this.Draw = CWCPolygonROI_Draw;
    this.Show = CWCPolygonROI_Show;
    this.Hide = CWCPolygonROI_Hide;
    this.GetRendererURL = CWCPolygonROI_GetRendererURL;
    this.GetROI = CWCPolygonROI_GetROI;
    this.GetRendererURL = CWCPolygonROI_GetRendererURL;
    this.Serialize = CWCPolygonROI_Serialize;

}
function CWCPolygonROI_Draw(){return null;}
function CWCPolygonROI_Show(){return null;}
function CWCPolygonROI_Hide(){return null;}
function CWCPolygonROI_GetRendererURL(){return null;}
function CWCPolygonROI_GetROI(){return null;}

function CWCPolygonROI_GetRendererURL()
{
    var szSerialized = this.Serialize();
    if (!szSerialized)
        return false;
        
    var szURL = this.manager.GetRendererURL();
    
    szURL = szURL + "&" + szSerialized;
    return szURL;
}

function CWCPolygonROI_Serialize()
{ 
    // init vars
    var szCoords = "";
    var szURL;
    var aTmp;
    
    // loop and build string of coordinates
    for ( var i=0; i < this.aNodeCoords.length; i++ )
    {
        // convert to ground units
        aTmp = this.manager.Pix2Geo( (this.aNodeCoords[i][0]- this.left), 
            ( this.aNodeCoords[i][1] - this.top ) );

        // store
        szCoords += aTmp[0] + ',' + aTmp[1];
        
        //szCoords += (this.aNodeCoords[i][0]  + ',' + ( this.aNodeCoords[i][1] - this.top);

        // add separator if necessary
        if ( i < this.aNodeCoords.length - 1 )
            szCoords += ',';
    }
    this.geoCoords = szCoords; // keep a record of the geographic nodes

    szURL = "type=" + this.type;
    szURL = szURL + "&mode=" + this.mode;
    szURL = szURL + "&coords=" + szCoords;
    szURL = szURL + "&edgecolor=" + escape(this.edgeColor);
    szURL = szURL + "&edgewidth=" + this.edgeWidth;
    szURL = szURL + "&fillcolor=" + escape(this.fillColor);
    if (CWCIsIE)
    {
        szURL = szURL + "&fillopacity=-1";
    }
    else
    {
        szURL = szURL + "&fillopacity=" + this.fillOpacity;
    }
    return szURL;
}
