
/**
 * $id$
 * @author jakub
 */

var current_polyline;

var LSI_LineHelper = Class.create();
LSI_LineHelper.prototype = {
    
    lsiworkstatus_colors: [],
    lsitrafficchanges_size: [],
    lsiworktype_style: [],
        
    initialize: function(){		
	        
        this.lsiworkstatus_colors['pln'] = '#556B4E';
        this.lsiworkstatus_colors['sht'] = '#FF702E';
        this.lsiworkstatus_colors['wrk'] = '#D4839E';
        this.lsiworkstatus_colors['hld'] = '#B34E20';
        this.lsiworkstatus_colors['ver'] = '#FFD92E';
        this.lsiworkstatus_colors['utl'] = '#015C65';
        this.lsiworkstatus_colors['end'] = '#5EC4CD';
        this.lsiworkstatus_colors['cls'] = '#888888';
	
        this.lsitrafficchanges_size['bu'] =  8;
        this.lsitrafficchanges_size['sam'] = 8;
        this.lsitrafficchanges_size['km'] = 8;
        this.lsitrafficchanges_size['cpj'] = 16;
        this.lsitrafficchanges_size['fpj'] = 12;
        this.lsitrafficchanges_size['out'] = 8;
        this.lsitrafficchanges_size['na'] = 8;
        
        this.lsiworktype_style['wkp'] = 'solid';
        this.lsiworktype_style['krk'] = 'dash';
        this.lsiworktype_style['rkw'] = 'dash';
        this.lsiworktype_style['cmn'] = 'dash';
        this.lsiworktype_style['rwr'] = 'dash';
        this.lsiworktype_style['mkt'] = 'dash';
        this.lsiworktype_style['na'] = 'solid';
    },
	
    /**
     * Calculates size of polyline against the current zoom level
     * @param Polyline polyline
     */
    calculateSizeAgainstZoom: function(polyline, zoom_level){
        var modifier = 0 - 19 % zoom_level 
        var size = this.lsitrafficchanges_size[polyline.road_block] + modifier;
        return  size;	
    },
	
    getColourForState: function (state){		
        return this.lsiworkstatus_colors[state];
    },
	
    getSizeForRoadBlock: function (road_block){		
        return this.lsitrafficchanges_size[road_block];
    },
    
    getLineStyleForWorkType: function (lsiworktype) {
        return this.lsiworktype_style[lsiworktype];
    }
    
}

LineHelper = new LSI_LineHelper;

var LSI_LineEditor = Class.create();
LSI_LineEditor.prototype = {
    current_line: false,
    polylines: [],   
    map:false,
    master_editable:false,
    
    initialize: function(map, polylines) {
        this.map = map;
        this.polylines = polylines;
        this.initControls();
        if ($('editable') || get_url_param('editable', window.location.href ) ) {
            var editable = get_url_param('editable', window.location.href ) == 'true';
            if (!editable) {
                $$('.edit_controls').each(function(item) {
                    item.select('a').each(function(link) {
                        if (!link.hasClassName('close')) {
                            link.up('li').hide();
                        }
                    });
                });
            }

            if ($('editable')) {
                editable = $F('editable') == 'true';
            }
            this.master_editable = editable;
        }
    },
    
    registerLine: function (pl){
        this.map.disableDoubleClickZoom();       
        if (pl) {

            //globalny handler ktory musi byc zdjety z globalnego obiektu mapy aby tworzene nowej linii dzialalo!!!
            if (click_listener !== false) {
                GEvent.removeListener(click_listener);
            }

            if (!$(mapa.map_container_id).hasClassName('noLines')) {
                var polyline = new GPolyline(pl.pts, LineHelper.getColourForState(pl.state), LineHelper.getSizeForRoadBlock(pl.road_block), 0.8);
                polyline.state = pl.state
                polyline.road_block = pl.road_block;
                polyline.lsiworktype = pl.lsiworktype;
                polyline.lsinetworktype_value = pl.lsinetworktype_value;
                polyline.overlay_id = pl.overlay_id;
                polyline.street = pl.street;
                polyline.from_value = pl.from_value;
                polyline.to_value = pl.to_value;
                polyline.description = pl.description;
                polyline.worktype_value = pl.worktype_value;
                polyline.networktype_value_text = pl.networktype_value_text;
                polyline.clickable = pl.clickable;
                polyline.editable = pl.editable

                polyline.pts = pl.pts;
                this.map.addOverlay(polyline);
                if (this.master_editable) polyline.enableEditing();
                this.current_line = polyline;
                this.current_line_template = this.clonePolyline(polyline, true);
                GEvent.addListener(polyline, "lineupdated", function(){
                    //GLog.write('lineupdated');
                
                    this.current_line = polyline;
                    this.saveLineToPost(this.current_line);
                }.bind(this));
            }
        
            mapa.resetMapFromBounds();
        }
    },

    registerNewLine: function (polyline){       
        this.current_line = polyline;
        var editor = this;
        GEvent.addListener(polyline, "lineupdated", function(){
            this.saveLineToPost(this.current_line);
        }.bind(this));        
    },
    
    hideMessages: function () {
        $$('div.messages ul').invoke('remove');
    },
    
    /*
     *NOTE: if needed to edit couple lines, in view there need to be pointList_lineID field 
     **/
    saveLineToPost: function (polyline) {
        
        var pointListInput = $('pointList_'+polyline.overlay_id);
        if (!pointListInput)
        {
            pointListInput = $('pointList');
        }
        if (pointListInput) {
            var pts_count = polyline.getVertexCount();
            var pts_list = '';
            for (var i = 0; i < pts_count; i++) {
                var pt = polyline.getVertex(i);
                pts_list = pts_list+pt.lat()+':'+pt.lng()+';';                            
            }
            pointListInput.value = pts_list;
        }
    },

    cleanPostForLine: function (polyline) {
        var pointListInput = $('pointList_'+polyline.overlay_id);
        if (!pointListInput)
        {
            pointListInput = $('pointList');
        }
        if (pointListInput) {           
            pointListInput.value = '';
        }
    },
	
    changeState: function (polyline) {
        polyline.setStrokeStyle({
            weight: LineHelper.calculateSizeAgainstZoom(this.polylines[i], this.map.getZoom())
        })		
    },

    initControls: function() {
        $$('a.reset').each(function(item) {
            item.observe('click', function(event) {
                event.stop();
                this.handleReset();
            }.bind(this))
        }.bind(this));

        $$('a.clean').each(function(item) {
            item.observe('click', function(event) {
                event.stop();
                this.handleClean();
            }.bind(this))
        }.bind(this));

        $$('a.close').each(function(item) {
            item.observe('click', function(event) {
                event.stop();
                this.handleClose();
            }.bind(this))
        }.bind(this));

        $$('a.edit').each(function(item) {
            item.observe('click', function(event) {
                event.stop();
                this.handleEdit();
            }.bind(this))
        }.bind(this));

        $$('a.new').each(function(item) {
            item.observe('click', function(event) {
                event.stop();
                this.handleNew();
            }.bind(this))
        }.bind(this));


        $$('a.help').each(function(item) {
            $$('div.help_container').invoke('hide');
            item.observe('click', function(event) {
                event.stop();
                this.handleHelp();
            }.bind(this))
        }.bind(this));
    },

    handleClean: function() {

        //initialize manual entry!
        this.hideMessages();
        if  (this.current_line) {
            this.removePolyline(this.current_line);
        }
    },
    
    handleReset: function()  {
        // clean up manual entry if any;;

        this.hideMessages();
        this.removePolyline(this.current_line);
        var polyline = this.clonePolyline(this.current_line_template, true);
        
        this.map.addOverlay(polyline);
        if (this.master_editable) polyline.enableEditing();
        this.registerNewLine(polyline)
        this.saveLineToPost(this.current_line);
    },

    handleNew: function()  {
        // clean up manual entry if any;;

        this.hideMessages();
        if  (this.current_line) {
            var alert=confirm("Aktualnie edytowana linia zostanie bezpowrotnie usunięta. Czy kontynuować??");
            if (alert)
                this.removePolyline(this.current_line);
            else {
                return false;
            }
            var polyline = this.clonePolyline(this.current_line_template, false);
        }
        else {
            var new_polyline = new GPolyline(pts, LineHelper.getColourForState(polyline.state), LineHelper.getSizeForRoadBlock(polyline.road_block), 1.0);//,'', LineHelper.getLineStyleForWorkType(polyline.lsiworktype))
        }
        this.map.addOverlay(polyline);
        polyline.enableDrawing();
        var editor = this;

        GEvent.addListener(polyline, "endline", function(){
            //GLog.write('lineupdated');
            if (this.master_editable) polyline.enableEditing();
            editor.registerNewLine(polyline)
            editor.saveLineToPost(polyline, true);
        });
    },

    handleClose: function()  {
        //present some dialog box asking if we are really done
        window.close();
    },

    handleEdit: function() {
        if (this.master_editable) this.current_line.enableEditing();
    },

    handleHelp: function(containter) {
        $$('div.help_container').each(function(item){
            Effect.toggle(item, 'blind', {
                duration: 0.2
            });
        }) 
    },

    removePolyline: function(polyline) {       
        polyline.disableEditing();
        polyline.setStrokeStyle({
            weight:0,
            opacity:0
        })
        this.cleanPostForLine(polyline);
        this.map.clearOverlays();
    },

    clonePolyline: function(polyline, populated) {
        var pts = polyline.pts;
        if (!populated) {
            pts = [];
        }
        // LineHelper.getColourForState(workstatus_class), LineHelper.getSizeForRoadBlock(triffichanges_class), 1.0,'', LineHelper.getLineStyleForWorkType(worktype_class))
        var new_polyline = new GPolyline(pts, LineHelper.getColourForState(polyline.state), LineHelper.getSizeForRoadBlock(polyline.road_block), 1.0)//,'', LineHelper.getLineStyleForWorkType(polyline.lsiworktype))

        new_polyline.state = polyline.state
        new_polyline.road_block = polyline.road_block;
        new_polyline.lsiworktype = polyline.lsiworktype;
        new_polyline.lsinetworktype = polyline.lsinetworktype;
        new_polyline.overlay_id = polyline.overlay_id;
        new_polyline.from_value = polyline.from_value;
        new_polyline.to_value = polyline.to_value;
        new_polyline.worktype_value = polyline.worktype_value;
        new_polyline.description = polyline.description;
        new_polyline.networktype_value_text = polyline.networktype_value_text;
        new_polyline.clickable = polyline.clickable;
        new_polyline.editable = polyline.editable;
  
        new_polyline.pts = polyline.pts;
   
        return new_polyline; 
    }

}
/**
 * Simple line manager
 */
var LSI_LineManager = Class.create();
LSI_LineManager.prototype = {
    map:false,
    polylines:[],
    default_zoom_lvl:14,
    states_hidden: [],
    line_editor:false,
   
    
    initialize: function(map, default_zoom_level){
        this.map = map;
        this.default_zoom_lvl = default_zoom_level;
        this.line_editor = new LSI_LineEditor(this.map);
    },
	
    /**
     * @param string state
     */
    showLinesByState: function (state) {
        this.states_hidden[state] = false;
        for (var i = 0; i < this.polylines.length; i++) {
            if (this.polylines[i].state == state) this.polylines[i].show();
        }
    },
	
    hideLinesByState: function (state) {
        this.states_hidden[state] = true;
        for (var i = 0; i < this.polylines.length; i++) {
            if (this.polylines[i].state == state) this.polylines[i].hide();
        }
    },
	
   
	
    /**
     * Registers polyline in manager
     *
     * Note: does not add polyline to the map
     * @param Polyline polyline
     */
    addLine: function (polyline) {
        if (polyline) {
            if (this.states_hidden[polyline.state] == true)
                polyline.hide();
			
            polyline.setStrokeStyle({
                weight: LineHelper.calculateSizeAgainstZoom(polyline, this.map.getZoom())
            })

            
            
            if (polyline.editable == true) {
                if (this.line_editor) {
                    this.line_editor.registerLine(polyline);
                //this.line_editor.polylines = this.polylines;
                }
            } else {
                this.polylines.push(polyline);
            }


		
        /*
             * If line is editable and there is a editable line container
             * add a link to centralize map over the line
             *
             * add a clik observer so it also sets the line as current
             * which will allow to modify its parameters
             *
             * add a polyline observer on update to save line vertexes as hidden inputs in a line container
             */
			
           
        }
    },
	
    /**
     * Recalculates wieght of all registered polylines against the current zoom level
     *
     * Route for optimization: hide 0 size lines
     * while unhiding make sure to unhide only visible lines
     */
    recalculateWeight: function () {
        for (var i = 0; i < this.polylines.length; i++) {
            this.polylines[i].setStrokeStyle({
                weight: LineHelper.calculateSizeAgainstZoom(this.polylines[i], this.map.getZoom())
            })
        }
    },
    
    findLinesInProximity: function (latlng) {
        var lines_in_proximity = [];        
        if (latlng) {
            var zoom = this.map.getZoom();
            var normalProj = G_NORMAL_MAP.getProjection();
            var threshold = 20; //pixels for proximity
            var mousePx = normalProj.fromLatLngToPixel(latlng, zoom);
            for (var p = 1; p < this.polylines.length; p++) {
                var minDist = threshold;                
                var routePixels = []                
                for (var n = 0; n < this.polylines[p].getVertexCount(); n++) {
                    var Px = normalProj.fromLatLngToPixel(this.polylines[p].getVertex(n), zoom);
                    routePixels.push(Px);
                }
                for (var n = 1; n < routePixels.length; n++) {
                    if (routePixels[n].x != routePixels[n - 1].x) {
                        var a = (routePixels[n].y - routePixels[n - 1].y) / (routePixels[n].x - routePixels[n - 1].x);
                        var b = routePixels[n].y - a * routePixels[n].x;
                        var dist = Math.abs(a * mousePx.x + b - mousePx.y) / Math.sqrt(a * a + 1);
					
                    }
                    else {
                        var dist = Math.abs(mousePx.x - routePixels[n].x)
                    };
				
                    // length^2 of line segment
                    var rl2 = Math.pow(routePixels[n].y - routePixels[n - 1].y, 2) + Math.pow(routePixels[n].x - routePixels[n - 1].x, 2);
				
                    // distance^2 of pt to end line segment
                    var ln2 = Math.pow(routePixels[n].y - mousePx.y, 2) + Math.pow(routePixels[n].x - mousePx.x, 2);
				
                    // distance^2 of pt to begin line segment
                    var lnm12 = Math.pow(routePixels[n - 1].y - mousePx.y, 2) + Math.pow(routePixels[n - 1].x - mousePx.x, 2);
				
                    // minimum distance^2 of pt to infinite line
                    var dist2 = Math.pow(dist, 2);
				
                    // calculated length^2 of line segment
                    var calcrl2 = ln2 - dist2 + lnm12 - dist2;
				
                    // redefine minimum distance to line segment (not infinite line) if necessary
                    if (calcrl2 > rl2) {
                        dist = Math.sqrt(Math.min(ln2, lnm12));
                    };
                    minDist = Math.min(minDist, dist);
                }
                if (minDist < threshold) {
                    lines_in_proximity.push(this.polylines[p]);
                }
            }
        }
        return lines_in_proximity;
        
    },
	 
    //TODO: needs implementation
    buildHtmlForLinesInProximity: function (lines_in_proximity)
    {
       
        var linelink = new Template ('<li><a href="#{overlay_id}" class="line_popup">#{street}, #{description}, #{type_value}</a></li>');
        var id = this.buildInfoWindowIdForLinesInProximity(lines_in_proximity);
        var container = document.createElement('DIV');
        container.innerHTML = "<p>W pobliżu znajdują się następujące remonty które mogą cię zainteresować</p>"
        container.setAttribute('id', "li_"+id);
        container = $(container);

        var ul = document.createElement('UL');
        ul.setAttribute('class', "prompt_links")
        ul = $(ul);

        for(var i = 0; i<lines_in_proximity.length; i++) {
            ul.insert(linelink.evaluate(
            {
                street: lines_in_proximity[i].street,
                overlay_id: lines_in_proximity[i].overlay_id,
                description: lines_in_proximity[i].description,
                type_value: lines_in_proximity[i].networktype_value_text
            }
            )
            );
        }

        container.insert(ul);
        return container;
    },
    //TODO: needs implementation
    buildInfoWindowIdForLinesInProximity: function (lines_in_proximity) {
        var id = "";
        for(var i = 0; i<lines_in_proximity.length; i++) {
            id = id + lines_in_proximity[i].overlay_id + "_";
        }
        id = id + this.map.getZoom();
        return id;
    }
}
