//////////////////////////////////////////////////////////////
//
// CCUtil contains a collection of graphical tool objects and generic utility function.
//
// CCUtil.selectionToolContainer: 
//   A container object that handles the creating, updating, utilizing and destroying of selecting/zooming tools, including Mark, Circle, Lasso 
//   and Rect. Each of the tools has constructor, update, toString and destroy functions.
//
//////////////////////////////////////////////////////////////


if (typeof(CCUtil) == "undefined"){
    var CCUtil = {};
    
    var _currentContext = this;
    var MAP_WIDTH, MAP_HEIGHT, SNAPDIST;    //map image dimention
    var surface;                            //surface object (created by dojox.gfx.createSurface()) on witch map image and graphical tools are displayed
    var MARK_X_OFFSET = 0;

    var COLOR_BLUE      = new dojo.Color("#0000be");        //dark blue
    var COLOR_GREEN     = new dojo.Color("#00be00");        //dark green
    var COLOR_RED       = new dojo.Color("#ff0000");        //bright red
    var COLOR_WHITE     = new dojo.Color("#ffffff");        //white 
    var COLOR_ORANGE    = new dojo.Color("#ff9f40");        //orange
    var MEASURE_COLOR   = new dojo.Color("#0000be");        //dark blue


    CCUtil.version = function(){
        return "1.2.0.0";
        }
        
    CCUtil.init = function (args) {
        MAP_WIDTH = args.map_width;
        MAP_HEIGHT = args.map_height;
        surface = args.surface;
        };


    CCUtil.selectionToolContainer = function (args) {
    
        SNAPDIST     = args.snapDist;

        this.shapeTypes = "Mark Lasso Circle Rect";

        this.Marks   = new Array();
        this.Lassos  = new Array();
        this.Circles = new Array();
        this.Rects   = new Array();
        
        this.lassoSegments = null;  //poly-lines of a un-finished lasso: when user is clicking on the map to
                                    //construct a lasso
                                    
        this.rect = null;
        this.mark = null;
        this.circle = null;
        this.radius = null;
        this.lasso = null;

    };


    ////////////////////////////////////
    //
    // mark object
    //
    ////////////////////////////////////
    CCUtil.selectionToolContainer.Mark = function(args) {
        this.body = args.Body;
        };

    CCUtil.selectionToolContainer.Mark.prototype.show = function() {
        if (this.body) this.body.moveToFront();
        };
        
    CCUtil.selectionToolContainer.Mark.prototype.update = function(args) {
        if (args.x == null || args.y == null ) return;
        if (this.body == null) return;
        
        this.body.rawNode.style.visibility   = "hidden";
        this.body = null;

        var mark_obj = create_mark_obj(surface, args);
        if (mark_obj != null) {
            mark_obj.rawNode.style.visibility   = "visible";

            this.body = mark_obj;
            }
        };

    CCUtil.selectionToolContainer.Mark.prototype.complete = function(args) {
        if (typeof this.body == 'undefined' || this.body == null) return;
        
        if (typeof args == 'undefined') args = {};
        if (typeof args.color == 'undefined') args.color = COLOR_BLUE;
        if (typeof args.weight == 'undefined') args.weight = 2; 
        
        this.body.setStroke({color: args.color, width: args.weight});
        };
        

    CCUtil.selectionToolContainer.Mark.prototype.toString = function() {
        if (this.body)
            return (this.body.getShape().points[0].x + MARK_X_OFFSET) + "|" + this.body.getShape().points[0].y;
        return "";
        };

    CCUtil.selectionToolContainer.Mark.prototype.destroy = function() {
        if (this.body) {
            this.body.rawNode.style.visibility   = "hidden";
            this.body = null;
            }
        };

    ////////////////////////////////////
    //
    // lasso object
    //
    ////////////////////////////////////
    CCUtil.selectionToolContainer.Lasso = function(args) {
        this.body = args.Body;
//        this.lasso = args.Lasso;
        this.rubberBand = args.Lasso;
        };

    CCUtil.selectionToolContainer.Lasso.prototype.show = function() {
        if (this.body) this.body.moveToFront();
        };
        

    //add a node of coordinate x,y
    CCUtil.selectionToolContainer.Lasso.prototype.addNode = function(args) {
        var clickx = args.x;
        var clicky = args.y;
        var i;
        
        if (clickx == null || clicky == null) return;

        var lasso_nodes = this.body.getShape().points;
        var node_length = lasso_nodes.length;

        if (node_length >=3) {
            //snap to the starting point
            if (Math.abs(lasso_nodes[0].x - clickx) < SNAPDIST)
                clickx = lasso_nodes[0].x;

            if (Math.abs(lasso_nodes[0].y - clicky) < SNAPDIST)
                clicky = lasso_nodes[0].y;
            }

        if (node_length > 0) //at least 2 points: p0 & p1
            {
            //don't record cuplicated point
            if (lasso_nodes[node_length-1].x != clickx ||
                lasso_nodes[node_length-1].y != clicky)
                lasso_nodes[node_length] = {x:clickx,y:clicky};

            }
        else
            lasso_nodes[node_length] = {x:clickx,y:clicky};

        //get updated node length
        node_length = lasso_nodes.length;
        var lasso_length = 0; //total length of lasso segments in pixels
        
        for (i=0; i < node_length-1; i++) {
            lasso_length += Math.sqrt((lasso_nodes[i].x - lasso_nodes[i+1].x) * (lasso_nodes[i].x - lasso_nodes[i+1].x) 
                                     +(lasso_nodes[i].y - lasso_nodes[i+1].y) * (lasso_nodes[i].y - lasso_nodes[i+1].y));
            }
            
        this.body.setShape(lasso_nodes);
        
        return lasso_length;
        };

    //show last segment in rubber shape
    CCUtil.selectionToolContainer.Lasso.prototype.update = function(args) {
        var cursorx = args.x;
        var cursory = args.y;

        if (cursorx == null || cursory == null) return;

        var lasso_nodes = this.body.getShape().points;
        var node_length = lasso_nodes.length;

        if (node_length >=3)
            {
            //snap to the starting point
            if (Math.abs(lasso_nodes[0].x - cursorx) < SNAPDIST)
                cursorx = lasso_nodes[0].x;

            if (Math.abs(lasso_nodes[0].y - cursory) < SNAPDIST)
                cursory = lasso_nodes[0].y;
            }


        if (node_length > 0) 
            this.rubberBand.setShape({x1:lasso_nodes[node_length-1].x, y1:lasso_nodes[node_length-1].y,x2:cursorx, y2:cursory});

        };

    CCUtil.selectionToolContainer.Lasso.prototype.complete = function(args) {
        if (typeof args == 'undefined') args = {};
        
        var autoClose = args.autoClose;
        var snapDist  = args.snapDist;
        
        var lasso_nodes = this.body.getShape().points;
        var node_length = lasso_nodes.length;

        if (node_length < 3) return;
        
        if (typeof autoClose == 'undefined') autoClose = true;
        if (typeof snapDist == 'undefined') snapDist = 5; //pixels
        
        //snap to the starting point
        //if the temp lasso has at least 4 points, and the last point is close enough to the first, then snap them together
        if (node_length > 3 &&
            Math.abs(lasso_nodes[node_length-1].x - lasso_nodes[0].x) < snapDist &&
            Math.abs(lasso_nodes[node_length-1].y - lasso_nodes[0].y) < snapDist)
            lasso_nodes[node_length-1] = lasso_nodes[0]; 
        //else if lasso should be closed, add a cloned point of the first
        else if (autoClose) 
            lasso_nodes[node_length] = lasso_nodes[0]; 

        this.body.setShape(lasso_nodes);
        this.body.setStroke({color: args.color, width: args.weight});
        
        this.rubberBand.rawNode.style.visibility   = "hidden";
        };

    CCUtil.selectionToolContainer.Lasso.prototype.isClosed = function(args) {
        var nodes = this.body.getShape().points; 
        var n_nodes = nodes.length;
        if (n_nodes <= 2) return false;

        if (nodes[0].x == nodes[n_nodes-1].x && nodes[0].y == nodes[n_nodes-1].y) return true;

        return false;
        };

    CCUtil.selectionToolContainer.Lasso.prototype.toString = function() {
        var j, lasso_string="";

        var nodes = this.body.getShape().points; 

        for (j=0; j< nodes.length; j++)
            {
            if (j ==0) lasso_string = lasso_string + nodes[j].x + "|" + nodes[j].y;
            else lasso_string = lasso_string + "|" + nodes[j].x + "|" + nodes[j].y;
            } 

        return lasso_string;
        };

    CCUtil.selectionToolContainer.Lasso.prototype.destroy = function() {

        if (this.body) {
            this.body.rawNode.style.visibility   = "hidden";
            this.body = null;
            }

        if (this.rubberBand) {
            this.rubberBand.rawNode.style.visibility   = "hidden";
            this.rubberBand = null;
            }
            
        this.lasso = null;
        };

    ////////////////////////////////////
    //
    // circle object
    //
    ////////////////////////////////////
    CCUtil.selectionToolContainer.Circle = function(args) {
        this.circle = args.Body;
        this.radius = args.Radius;

        this.color = MEASURE_COLOR;
        this.width = 2;
        this.max_radius = args.max_radius;

        var target_radius = parseFloat(args.target_radius); //in miles

        if (target_radius > 0) { //set circle radius to target length
            var max_radius = this.max_radius / MAP_WIDTH * args.map_width; //max radius in miles

            if (target_radius > max_radius) 
                target_radius = Math.round(max_radius * 100) / 100 ;

            var radius_pix  = Math.round(target_radius  / args.map_width * MAP_WIDTH);   // radius in pixel

            this.circle.setShape({r:radius_pix});
            this.radius.setShape({x2:this.radius.shape.x1 + radius_pix});

            }

        this.limit_left_x   = 0;
        this.limit_right_x  = MAP_WIDTH;
        this.limit_top_y    = 0;
        this.limit_bottom_y = MAP_HEIGHT;

        };

    CCUtil.selectionToolContainer.Circle.prototype.show = function() {
        if (this.circle) this.circle.moveToFront();
        if (this.radius) this.radius.moveToFront();
        };
        

    CCUtil.selectionToolContainer.Circle.prototype.update = function(args) {
        if (args.r == null ) return;
        if (args.unit == null) args.unit = "pixel";
        
        var r1 = args.r;
        var rmin1, rmin2;
        
        if (args.unit == "map_unit" && args.mapScope != null) { //needs to convert from map unit to pixel
            var scopeParts = args.mapScope.split(" ");
            if (scopeParts.length == 5) 
                r1 = Math.round(r1 * MAP_WIDTH / scopeParts[2]);
            }
            
        //limit radius of circle to be within the map image
        rmin1 = Math.min(this.radius.shape.x1, this.radius.shape.y1); 
        rmin2 = Math.min(MAP_WIDTH - this.radius.shape.x1, MAP_HEIGHT - this.radius.shape.y1);
        rmin1 = Math.min(rmin1, rmin2);
        r1 = Math.min(r1, rmin1);
        
        
        if (r1 >= this.max_radius)
            r1 = this.max_radius;

        var x = this.radius.shape.x1;
        var y = this.radius.shape.y1;

        this.circle.setShape({r:r1});
        this.radius.setShape({x1:x, y1:y, x2:x+r1, y2:y});
        
        if (args.unit == "map_unit" && args.mapScope != null) { 
            var scopeParts = args.mapScope.split(" ");
            
            if (scopeParts.length == 5) 
                return Math.round(r1 * scopeParts[2] / MAP_WIDTH * 100) / 100;
            else return null;
            }
        else return null;
        };

    CCUtil.selectionToolContainer.Circle.prototype.complete = function(args) {
        if (typeof this.circle == 'undefined' || this.circle == null) return;
        
        if (typeof args == 'undefined') args = {};
        if (typeof args.color == 'undefined') args.color = COLOR_BLUE;
        if (typeof args.weight == 'undefined') args.weight = 2; 
        
        this.circle.setStroke({color: args.color, width: args.weight});
        };
        
    CCUtil.selectionToolContainer.Circle.prototype.select = function(args) {
        if (args.x == null || args.y == null ) return;

        var isSelected = false;
        var x = this.radius.shape.x1;
        var y = this.radius.shape.y1;
        var r = this.circle.shape.r ;
        
        //selecting method: 'center' or 'inside'
        // center: user must click on or within the snap distance of the center of the circle to select
        // inside: user can click on any point within the circle to select
        if (args.method == 'inside')
            isSelected = ((x - args.x) * (x - args.x) + (y - args.y) * (y - args.y) <= r * r);
        else
            isSelected = (Math.abs(x - args.x) <= SNAPDIST && Math.abs(y - args.y) <= SNAPDIST);

        if (isSelected) {
            isSelected = true;
            var tmp = this.circle.getStroke();

            this.color = tmp.color;
            this.width = tmp.width;

            this.move_orig_x = this.radius.shape.x1;
            this.move_orig_y = this.radius.shape.y1; 
            this.limit_left_x   = this.circle.shape.r ;
            this.limit_right_x  = MAP_WIDTH -  this.limit_left_x;
            this.limit_top_y    = this.limit_left_x;
            this.limit_bottom_y = MAP_HEIGHT - this.limit_top_y;

            this.circle.setStroke({color: COLOR_RED, width:2});
            }

        return  isSelected;
        };
                             

    CCUtil.selectionToolContainer.Circle.prototype.move = function(args) {

        if (args.dx == null || args.dy == null ) return;

        var r = this.circle.shape.r ;

        circle_new_x = this.move_orig_x + args.dx;
        circle_new_y = this.move_orig_y + args.dy;


        if (circle_new_x > this.limit_left_x && circle_new_x < this.limit_right_x 
            && circle_new_y > this.limit_top_y && circle_new_y < this.limit_bottom_y
            ) 
            //move applies only when use clicks on within the rectangle
            {
            
            this.circle.setTransform({dx: circle_new_x, dy: circle_new_y});
            this.radius.setShape({x1:circle_new_x,y1:circle_new_y,x2:circle_new_x+r,y2:circle_new_y});
            }
        };

    //return circle radius value in miles
    CCUtil.selectionToolContainer.Circle.prototype.getRadius = function(args) {
        if (args.map_width == null  ) return;

        return(Math.round(this.circle.shape.r / MAP_WIDTH * args.map_width * 100)/100); //max radius in miles

        };

    //set circle radius to certain length in miles
    CCUtil.selectionToolContainer.Circle.prototype.setRadius = function(args) {

        if (args.radius == null || args.map_width == null  ) return;

        var r = this.circle.shape.r ;
        var target_width = args.radius; //in miles

        var max_r_pix_1 = this.radius.shape.x1; //left
        var max_r_pix_2 = this.radius.shape.y1; //top
        var max_r_pix_3 = MAP_WIDTH -1 - max_r_pix_1; //right
        var max_r_pix_4 = MAP_HEIGHT -1 - max_r_pix_2; //bottom
        
        var max_radius_pix = Math.min(max_r_pix_1, max_r_pix_2);
        max_radius_pix = Math.min(max_radius_pix,max_r_pix_3);
        max_radius_pix = Math.min(max_radius_pix,max_r_pix_4);
        
        var max_radius = max_radius_pix / MAP_WIDTH * args.map_width; //max radius in miles

        if (target_width > max_radius) 
            target_width = Math.round(max_radius * 100) / 100 ;

        var radius_pix  = Math.round(target_width  / args.map_width * MAP_WIDTH);   // radius in pixel

        this.circle.setShape({r:radius_pix});
        this.radius.setShape({x2:this.radius.shape.x1 + radius_pix});

        return target_width;
        };



    CCUtil.selectionToolContainer.Circle.prototype.deactivate = function() {
        this.circle.setStroke({color: this.color, width:this.width});
        }

    CCUtil.selectionToolContainer.Circle.prototype.toString = function() {
        return parseInt(this.radius.shape.x1) + "|" + parseInt(this.radius.shape.y1) + "|" 	+ parseInt(this.radius.shape.x2) + "|" + parseInt(this.radius.shape.y2) ;
        }

    CCUtil.selectionToolContainer.Circle.prototype.destroy = function() {
        if (this.circle) {
            this.circle.rawNode.style.visibility   = "hidden";
            this.circle = null;
            }

        if (this.radius) {
            this.radius.rawNode.style.visibility   = "hidden";
            this.radius = null;
            }
        };


    ////////////////////////////////////
    //
    // rect object
    //
    ////////////////////////////////////
    CCUtil.selectionToolContainer.Rect = function(args) {
        this.rect = args.Body;

        this.rect_shreshold = args.rect_shreshold; //the rect is treated as a point if width or height is less than this value
        this.x0 = this.rect.shape.points[0].x;
        this.y0 = this.rect.shape.points[0].y;
        this.color = MEASURE_COLOR;
        this.width = 2;
        };

    CCUtil.selectionToolContainer.Rect.prototype.show = function() {
        if (this.rect) this.rect.moveToFront();
        };
        
    CCUtil.selectionToolContainer.Rect.prototype.update = function(args) {
        var x1 = args.x, y1 = args.y;
        var x0 = this.x0, y0 = this.y0;

        if (x1 == null || y1 == null) return;

        this.rect.setShape([{x: x0, y: y0}, {x: x0, y: y1}, {x: x1, y: y1}, {x: x1, y: y0}, {x: x0, y: y0}]);			
        };

    CCUtil.selectionToolContainer.Rect.prototype.select = function(args) {
        if (args.x == null || args.y == null ) return;

        var isSelected = false;
        var i;
        var x, y;
        var nodes = this.rect.shape.points;

        for (i=0; i<nodes.length-1; i++) {    //last node is the same as the first
            x = nodes[i].x;
            y = nodes[i].y;

            if (Math.abs(x - args.x) <= SNAPDIST && Math.abs(y - args.y) <= SNAPDIST) {
                isSelected = true;
                var tmp = this.rect.getStroke();

                this.color = tmp.color;
                this.width = tmp.width;

                this.move_orig_nodes = this.rect.shape.points;
                this.move_orig_x = this.rect.shape.points[0].x;
                this.move_orig_y = this.rect.shape.points[0].y;
                this.rwidth      = this.rect.shape.points[2].x - this.rect.shape.points[0].x;
                this.rheight     = this.rect.shape.points[2].y - this.rect.shape.points[0].y;
                 
                this.rect.setStroke({color: COLOR_RED, width:2});
                }
            }

        return  isSelected;
        };
                             

    CCUtil.selectionToolContainer.Rect.prototype.move = function(args) {

        if (args.dx == null || args.dy == null ) return;

        var i;
        var nodes = this.rect.shape.points;

        var move_x = this.move_orig_x + args.dx;
        var move_y = this.move_orig_y + args.dy;


        if (move_x > 0 && move_x + this.rwidth < MAP_WIDTH
            && move_y > 0 && move_y + this.rheight < MAP_HEIGHT) {
            for (i=0; i<nodes.length; i++) {
                nodes[i].x = this.move_orig_nodes[i].x + args.dx;
                nodes[i].y = this.move_orig_nodes[i].y + args.dy;
                }
            this.rect.setShape(nodes);
            }
        };

    CCUtil.selectionToolContainer.Rect.prototype.regulate = function() {
    // rect nodes are supposed to be located at
    //  0,4     3
    //
    //
    //  1       2
    //
        var x0 = this.rect.shape.points[0].x;
        var y0 = this.rect.shape.points[0].y;
        var x2 = this.rect.shape.points[2].x;
        var y2 = this.rect.shape.points[2].y;

        var orig_x = Math.min(x0,x2);
        var orig_y = Math.min(y0,y2);
        var corner_x = Math.max(x0,x2);
        var corner_y = Math.max(y0,y2);

        var width = corner_x - orig_x;
        var height = corner_y - orig_y;

        //just a simple click without draging
        if (width <= this.rect_shreshold)
            width = 0;
        if (height <= this.rect_shreshold)
            height = 0;

        this.rect.rawNode.style.visibility   = "hidden";
        this.rect = null;
        this.rect = surface.createPolyline([{x: orig_x, y: orig_y}, {x: orig_x, y: corner_y}, {x: corner_x, y: corner_y}, {x: corner_x, y: orig_y}, {x: orig_x, y: orig_y}])
                            .setStroke({color: "black"});
        return this;
        };

    CCUtil.selectionToolContainer.Rect.prototype.deactivate = function() {
        this.rect.setStroke({color: this.color, width:this.width});
        }

    CCUtil.selectionToolContainer.Rect.prototype.toString = function() {
        this.regulate();

        var x0 = this.rect.shape.points[0].x;
        var y0 = this.rect.shape.points[0].y;
        var x2 = this.rect.shape.points[2].x;
        var y2 = this.rect.shape.points[2].y;

        //UL_x|UL_y|width|height	
        return parseInt(x0) + "|" + parseInt(y0) + "|" + parseInt(x2 - x0) + "|" + parseInt(y2 - y0);
        };

    CCUtil.selectionToolContainer.Rect.prototype.destroy = function() {
        if (this.rect) {
            this.rect.rawNode.style.visibility   = "hidden";
            this.rect = null;
            }

        };




    ////////////////////////////////////
    //
    // selectionToolContainer functions
    //
    ////////////////////////////////////

    CCUtil.selectionToolContainer.prototype.createLasso = function (args) {
                                        
        if (surface) {

            if (typeof args.lassoColor == 'undefined') args.lassoColor = COLOR_BLUE;
            if (typeof args.lassoWeight == 'undefined') args.lassoWeight = 1
            
            if (typeof args.tailColor == 'undefined') args.tailColor = COLOR_RED;
            if (typeof args.tailWeight == 'undefined') args.tailWeight = 1

            var tempLassoBody = surface.createPolyline(null)
//                .setFill([0, 0, 0, 0.01]);
                .setStroke({color:[255, 25, 55, 1.0], width:1} );

            tempLassoBody.setStroke({color: args.lassoColor, width: args.lassoWeight});       

            var lasso_nodes =  tempLassoBody.getShape().points;
            lasso_nodes[0] = {x:args.x, y:args.y};
            tempLassoBody.setShape(lasso_nodes);

            tempLassoBody.rawNode.style.visibility   = "visible";

            var tempLassoTail = surface.createLine({x1: args.x, y1: args.y, x2: args.x, y2: args.y})
                .setStroke({color:args.tailColor, width: args.tailWeight} );
            tempLassoTail.rawNode.style.visibility   = "visible";
        
            
            args = {
                "Body": tempLassoBody,
                "Lasso": tempLassoTail}

            this.lassoSegments = new CCUtil.selectionToolContainer.Lasso(args);
            this.lasso = null;
            //return this.LassoSegments;
            }

        return null;
    };

    CCUtil.selectionToolContainer.prototype.createMark = function (args) {
                                        
        if (surface) {
            var mark_obj = create_mark_obj(surface, args);
            if (mark_obj != null) {
                mark_obj.rawNode.style.visibility   = "visible";

                this.mark =  new CCUtil.selectionToolContainer.Mark({"Body":mark_obj});
                }
            }

        return null;
    };


    CCUtil.selectionToolContainer.prototype.createCircle = function (args) {
                                        
        if (surface) {

            var circle_obj = surface.createCircle({r: 1})
                    .setStroke({color:[0, 0, 0, 1.0], width:1} );
            circle_obj.setTransform({dx: 1, dy: 1});
            circle_obj.setShape({r:1});

            var circle_radius_obj = surface.createLine({x1: 0, y1: 0, x2: 0, y2: 0})
                    .setStroke({color:[255, 25, 55, 1.0], width:1} );

            circle_obj.setShape({r:1});
            circle_obj.setTransform({dx: args.x, dy: args.y});

            circle_radius_obj.setShape({x1:args.x,y1:args.y,x2:args.x,y2:args.y});

            circle_obj.rawNode.style.visibility   = "visible";
            circle_radius_obj.rawNode.style.visibility   = "visible";

        
            args = {
                "Body": circle_obj,
                "Radius": circle_radius_obj,
                "max_radius": args.max_radius,
                "map_width": args.map_width,
                "target_radius": args.target_radius}
            this.circle = new CCUtil.selectionToolContainer.Circle(args);

            }

        return null;
    };


    CCUtil.selectionToolContainer.prototype.createRect = function (args) {
                                        
        if (surface) {
            var x0 = args.x, y0 = args.y;
            if (x0 == null || y0 == null) return null;

            var rect_obj = surface.createPolyline([{x: 1, y: 1}, {x: 1, y: 1}, {x: 1, y: 1}, {x: 1, y: 1}, {x: 1, y: 1}])
                            .setStroke({color: "black"});
            rect_obj.setShape([{x: x0, y: y0}, {x: x0, y: y0}, {x: x0, y: y0}, {x: x0, y: y0}, {x: x0, y: y0}]);			

            rect_obj.rawNode.style.visibility   = "visible";

//            return (new CCUtil.selectionToolContainer.Rect({"Body": rect_obj, rect_shreshold: args.rect_shreshold}));

            this.rect = new CCUtil.selectionToolContainer.Rect({"Body": rect_obj, rect_shreshold: args.rect_shreshold});
            }

        return null;
    };

    CCUtil.selectionToolContainer.prototype.completeLasso = function(lasso_item, args) {

        if (lasso_item == null ) return null;
    
        if (typeof (args) != 'object') args={};
        if (typeof args.color == 'undefined') args.color = COLOR_BLUE;
        if (typeof args.weight == 'undefined') args.weight = 2
  
        lasso_item.complete(args);
        this.lasso = lasso_item;
        };


    //add tool object to container 
    CCUtil.selectionToolContainer.prototype.addLasso = function(lasso_item, args) {

        if (lasso_item == null ) return null;
    
        if (typeof (args) != 'object') args={};
        if (typeof args.color == 'undefined') args.color = COLOR_BLUE;
        if (typeof args.weight == 'undefined') args.weight = 2
  
        lasso_item.complete(args);
        this.lasso = lasso_item;
          
        var npoints = this.Lassos.length;
        this.Lassos[npoints] = lasso_item;
        this.lassoSegments = null;
        };

    CCUtil.selectionToolContainer.prototype.addMark = function(mark_item, args) {

        if (mark_item == null ) return null;
    
        if (typeof (args) != 'object' || args == null) args = {};
    
        //mark_item.body.setStroke({color: args.color, width: args.weight})

        if (!args.info_tool) {
            var npoints = this.Marks.length;
            this.Marks[npoints] = mark_item;
            }
        };

    CCUtil.selectionToolContainer.prototype.addCircle = function(circle_item, args) {

        if (circle_item == null ) return null;
    
        if (typeof (args) != 'object') return null;
        
        if (circle_item.circle.shape.r < 1) return;
            
        circle_item.circle.setStroke({color: args.circle_color, width: args.circle_weight})

        var npoints = this.Circles.length;
        this.Circles[npoints] = circle_item;
        };


    CCUtil.selectionToolContainer.prototype.addRect = function(rect_item, args) {

        if (rect_item == null ) return null;
    
        if (typeof (args) != 'object') return null;
     
        rect_item = rect_item.regulate();

        rect_item.rect.setStroke({color: args.color, width: args.weight})

        var npoints = this.Rects.length;
        this.Rects[npoints] = rect_item;
        };


    CCUtil.selectionToolContainer.prototype.addRect = function( args) {

        if (typeof (args) != 'object') return null;
        rect_item = this.rect;
        rect_item = rect_item.regulate();

        rect_item.rect.setStroke({color: args.color, width: args.weight})

        var npoints = this.Rects.length;
        this.Rects[npoints] = rect_item;
        this.rect = null;
        };




    CCUtil.selectionToolContainer.prototype.selectCircle = function(args) {
        var i;
        var circle_obj;

        if (typeof (args) != 'object') return null;
    
        var npoints = this.Circles.length;
        if (npoints == 0) return null;

        if (args.method == null) args.method = 'center';

        for (i=0; i< npoints; i++) {
            circle_obj = this.Circles[i];
            if (circle_obj.select({x:args.x, y:args.y, method:args.method})) return circle_obj;
            }

        return null;
        };

    CCUtil.selectionToolContainer.prototype.selectRect = function(args) {
        var i;
        var circle_obj;

        if (typeof (args) != 'object') return null;
    
        var npoints = this.Rects.length;
        if (npoints == 0) return null;

        for (i=0; i< npoints; i++) {
            rect_obj = this.Rects[i];
            if (rect_obj.select({x:args.x, y:args.y})) return rect_obj;
            }

        return null;
        };

    CCUtil.selectionToolContainer.prototype.existsMark = function() {
        if (typeof(this.mark) == 'undefined') return false;
        if (this.mark && this.mark.body) return true;
        if (this.Marks.length > 0) return true;
        return false;
        };

    CCUtil.selectionToolContainer.prototype.existsRect = function() {
        if (typeof(this.rect) == 'undefined') return false;
        if (this.rect) return true;
        if (this.Rects.length > 0) return true;
        return false;
        };

    CCUtil.selectionToolContainer.prototype.existsCircle = function() {
        if (typeof(this.circle) == 'undefined') return false;
        if (this.circle && this.radius) return true;
        if (this.Circles.length > 0) return true;
        return false;
        };

    CCUtil.selectionToolContainer.prototype.isEmpty = function(tool_type) {

        var nmarks = this.Marks.length;
        var nlassos = this.Lassos.length;
        var ncircles = this.Circles.length;
        var nrects = this.Rects.length;

        switch (tool_type) 
            {
            case 'Mark':
                if (nmarks > 0) return false;
                break;

            case 'Lasso':
                if (nlassos > 0) return false;
                if (this.lassoSegments) return false;
                break;
            
            case 'Circle':
                if (ncircles > 0) return false;
                break;
            
            case 'Rect':
                if (nrects > 0) return false;
                break;

            default: //the container is not empty if any of the tool objects is present
                if (nmarks + nlassos + ncircles + nrects > 0) return false;
            }

        return true;
        };


    CCUtil.selectionToolContainer.prototype.clearAll = function() {
        var  obj;

        while (this.Marks.length > 0) {
            obj = this.Marks.pop();
            if (obj) {
                obj.destroy();
                obj = null;
                }
            }
        if (this.mark) {
            this.mark.destroy();
            this.mark = null;
            }
            
        while (this.Lassos.length > 0) {
            obj = this.Lassos.pop();
            if (obj) {
                obj.destroy();
                obj = null;
                }
            }
        if (this.lassoSegments) {
            this.lassoSegments.destroy();
            this.lassoSegments = null;
            }

        if (this.lasso) {
            this.lasso.destroy();
            this.lasso = null;
            }

        while (this.Circles.length > 0) {
            obj = this.Circles.pop();
            if (obj) {
                obj.destroy();
                obj = null;
                }
            }
        if (this.circle) {
            this.circle.destroy();
            this.circle = null;
            }
            
        while (this.Rects.length > 0) {
            obj = this.Rects.pop();
            if (obj) {
                obj.destroy();
                obj = null;
                }
            }
        };

    CCUtil.selectionToolContainer.prototype.generateSelectingString = function() {
        var i, obj, obj_arr;
        var selectingString = "";
        var delimiter = "@";

        if (this.Marks.length > 0) {obj_arr = this.Marks; delimiter="|";}
        else if (this.Lassos.length > 0) obj_arr = this.Lassos;
        else if (this.lasso) obj_arr = new Array(this.lasso);
        else if (this.Circles.length > 0) obj_arr = this.Circles;
        else if (this.circle) obj_arr = new Array(this.circle);
        else if (this.Rects.length > 0) obj_arr = this.Rects;
        else return "";

        for (i=0; i< obj_arr.length; i++) {
            obj = obj_arr[i];
            if (obj) {
                if (i ==0) selectingString = selectingString + obj.toString();
                else selectingString = selectingString + delimiter + obj.toString();
                }
            }


        return selectingString;

        };

    CCUtil.selectionToolContainer.prototype.show = function() {
        var i, obj, obj_arr;

        if (this.Marks.length > 0) obj_arr = this.Marks; 
        else if (this.Lassos.length > 0) obj_arr = this.Lassos;
        else if (this.lasso) obj_arr = new Array(this.lasso);
        else if (this.Circles.length > 0) obj_arr = this.Circles;
        else if (this.circle) obj_arr = new Array(this.circle);
        else if (this.Rects.length > 0) obj_arr = this.Rects;

        if (!obj_arr) return;
        
        for (i=0; i< obj_arr.length; i++) {
            obj = obj_arr[i];
            if (obj) obj.show();
            }
        };



    //private functions  
    var create_mark_obj = function(surface, args) {
        var mark_obj = null;
        var npoints = 0;
    
        click_x = args.x;
        click_y = args.y;

        if (typeof(click_x) == 'undefined' || typeof(click_y) == 'undefined')
            return null;

        if (typeof(click_x) == 'string') 
            click_x = parseInt(click_x);
        if (typeof(click_y) == 'string') 
            click_y = parseInt(click_y);
                                                  
        var x0 = click_x;
        var xm5 = click_x - 5 < 0 ? 0 : click_x - 5;
        var xm8 = click_x - 8 < 0 ? 0 : click_x - 8;
        var xp5 = click_x + 5 > MAP_WIDTH ? MAP_WIDTH : click_x + 5;
        var xp8 = click_x + 8 > MAP_WIDTH ? MAP_WIDTH : click_x + 8;

        var y0 = click_y;
        var ym5 = click_y - 5 < 0 ? 0 : click_y - 5;
        var ym8 = click_y - 8 < 0 ? 0 : click_y - 8;
        var yp5 = click_y + 5 > MAP_HEIGHT ? MAP_HEIGHT : click_y + 5;
        var yp8 = click_y + 8 > MAP_HEIGHT ? MAP_HEIGHT : click_y + 8;
                        
        if (surface) {
            mark_obj = surface.createPolyline([{x: xm8, y: y0}, {x: xp8, y: y0}, {x: x0, y: y0}, {x: x0, y: ym8},{x: x0, y: yp8},{x: x0, y: yp5},
                                            {x: xm5, y: y0},{x: x0, y: ym5},{x: xp5, y: y0},{x: x0, y: yp5}])

              .setStroke({color: COLOR_RED});
        
            return mark_obj;
            }
    
        return null;
    };









    var create_lasso_obj = function (surface, args) {
        var lasso_obj = null;
        var nlassos = 0;

        if (surface) {
            lasso_obj = surface.createPolyline(null)
                .setFill([0, 0, 0, 0.01]);

            lasso_obj.setStroke({color: args.color, width: args.weight});       

            if (typeof(args.shapeCoords) != 'undefined' && args.shapeCoords.length > 1)
                lasso_obj.setShape(args.shapeCoords);

            return lasso_obj ;
            }

        return null;
    };


//////////////////////////////////
//
//Javascript generic utililies
//
//////////////////////////////////

    CCUtil.isIE = function () {
        var brw = navigator.userAgent;
        return(brw.indexOf("MSIE") >=0);
    };

    CCUtil.arrayToObj = function (in_arr) {
        var out_obj = new Array();
        var i;
        
        if ( typeof(in_arr) != 'object' || in_arr == null) return null;
        
        if (in_arr.length % 2 != 0) return null;
        
        for (i=0;i<in_arr.length; i += 2) 
            {
            out_obj[in_arr[i]] = in_arr[i+1];
            }
            
        return out_obj;
        };

    CCUtil.getTopPosition = function  (iElement) {
        var oNode = iElement;
        var iTop = 0;
     
        if (typeof(iElement) != "object") return 0;

        while(iElement.tagName != "BODY") {
            iTop += iElement.offsetTop;
            iElement = iElement.offsetParent;
            }

        return iTop;
    };


    CCUtil.getElementPosition = function (el) {
        var offsetTrail = el;     
        var offsetLeft = 0;
        var offsetTop = 0;

        if (typeof(el) != "object") return {left:offsetLeft, top:offsetTop};

        while (offsetTrail) {
            offsetLeft += offsetTrail.offsetLeft;
            offsetTop += offsetTrail.offsetTop;
            offsetTrail = offsetTrail.offsetParent;
        };

        if (navigator.userAgent.indexOf("Mac") != -1 && 
            typeof document.body.leftMargin != "undefined") {
            offsetLeft += document.body.leftMargin;
            offsetTop += document.body.topMargin;
        }
        return {left:offsetLeft, top:offsetTop};
    };


    CCUtil.getElementsByClassName = function (classname, node) {
        if(!node) node = document.getElementsByTagName("body")[0];
        var a = [];
        var re = new RegExp('\\b' + classname + '\\b');
        var els = node.getElementsByTagName("*");
        for(var i=0,j=els.length; i<j; i++)
        if(re.test(els[i].className))a.push(els[i]);
        return a;
    };


    [].indexOf || (Array.prototype.indexOf = function(v,n){
      n = (n==null)?0:n; var m = this.length;
      for(var i = n; i < m; i++)
        if(this[i] == v)
           return i;
      return -1;
    });

    String.prototype.trim = function () {
    return this.replace(/^\s*/, "").replace(/\s*$/, "")};
    
};
    

