function Planejamento(viewModel, controleMapa) {
    this.Desvios = [];
    this.Enlaces = [];
    this.Terminais = [];
    this.PontosControle = [];

    this.Mapa = controleMapa.map;

    this.viewModel = viewModel;

    this._isShowing = false;

    this.IsShowing = function () {
        return this._isShowing;
    };
    
    this.DescricaoLinha = viewModel.DescricaoLinha;
    this.bounds = new google.maps.LatLngBounds();
};

Planejamento.prototype.Cor = function () {
    return this.viewModel.CorEnlace;
};

Planejamento.prototype.ChangeColor = function (cor) {
    this.viewModel.CorEnlace = cor;
    if (this.Enlaces.length > 0) {
        for (var i in this.Enlaces)
            this.Enlaces[i].setOptions({ strokeColor: cor });
        for (var i in this.Desvios)
            this.Desvios[i].setOptions({ strokeColor: cor });
    }
};

Planejamento.prototype.Show = function () {
    this._isShowing = true;
    if (this.Terminais.length > 0) {
        this.setMap(this.Desvios, this.Mapa);
        this.setMap(this.Enlaces, this.Mapa);
        this.setMap(this.Terminais, this.Mapa);
        this.setMap(this.PontosControle, this.Mapa);
    } else if (this.viewModel != null) {
        for (var i in this.viewModel.Formas) {
            this.plotarPlanejamentoTerminal(this.viewModel.Formas[i]);
        }
        for (var i in this.viewModel.Controles) {
            this.plotarPlanejamentoPontosControle(this.viewModel.Controles[i]);
        }
        this.plotarPlanejamentoEnlaces();
    }
    //this.Mapa.fitBounds(this.bounds);
    //this.Mapa.setZoom(12);
};


Planejamento.prototype.Hide = function () {
    this._isShowing = false;
    this.setMap(this.Desvios);
    this.setMap(this.Enlaces);
    this.setMap(this.Terminais);
    this.setMap(this.PontosControle);
};

Planejamento.prototype.setMap = function (array, map) {
    for (var i in array)
        array[i].setMap(map);
};

Planejamento.prototype.plotarPlanejamentoEnlaces = function () {
    for (var h in this.viewModel.Enlaces) {
        this.plotarPlanejamentoEnlace(this.viewModel.Enlaces[h].LinhasEnlacesItinerarios, this.viewModel.CorEnlace, this.viewModel.Enlaces[h].Descricao, this.viewModel.Enlaces[h].Codigo);
    }

    for (var h in this.viewModel.EnlacesDesvios) {
        this.plotarPlanejamentoEnlaceDesvio(this.viewModel.EnlacesDesvios[h], this.viewModel.CorEnlace);
    }
};

Planejamento.prototype.plotarPlanejamentoEnlaceDesvio = function(enlaceDesvio, cor) {
    var forma = null;
    var pts = [];

    if (enlaceDesvio.Pontos == null || enlaceDesvio.Pontos == undefined)
        return null;

    for (var j = 0; j < enlaceDesvio.Pontos.length; j++) {
        pts.push(new google.maps.LatLng(enlaceDesvio.Pontos[j].Latitude / 1000000, enlaceDesvio.Pontos[j].Longitude / 1000000));
    }

    var objetoForma = new PolilinhaPlanejamentoVeiculo({
        mapa: this.Mapa,
        pontos: pts,
        cor: cor,
        lineSymbol: lineSymbolplanejamento,
    });

    forma = CriarPolilinha(objetoForma);

    if (forma != null) {
        forma.setMap(this.Mapa);
        
        this.Desvios.push(forma);
    }
    return pts;
}

Planejamento.prototype.plotarPlanejamentoEnlace = function (LinhasEnlacesItinerarios, cor, descricao, codigoEnlace) {
    var forma = null;
    var pts = [];
    var mSelf  = this;

    for (var j = 0; j < LinhasEnlacesItinerarios.length; j++) {
        var latLng = new google.maps.LatLng(LinhasEnlacesItinerarios[j].Latitude / 1000000, LinhasEnlacesItinerarios[j].Longitude / 1000000);
        pts.push(latLng);
        //mSelf.bounds.extend(latLng);
    }
    //"#5570CC"
    var objetoForma = new PolilinhaPlanejamentoVeiculo({
        mapa: this.Mapa,
        pontos: pts,
        cor: cor,
        lineSymbol: lineSymbolplanejamento,
    });

    forma = CriarPolilinha(objetoForma);

    if (forma != null) {

        forma.Descricao = descricao;
        forma.Codigo = codigoEnlace;

        google.maps.event.addListener(forma, 'click', function (evt) { mSelf.ClickPolilinhaPlanejamento(evt, this); });
        
        this.Enlaces.push(forma);
    }
};

Planejamento.prototype.plotarPlanejamentoTerminal = function (forma) {
    var mSelf = this;
    var formaobj = null;
    switch (forma.Tipo) {
        case 1: // poligono
            var pts = [];

            for (var j = 0; j < forma.Coordenadas.length; j++) {
                var ptAux = new google.maps.LatLng(forma.Coordenadas[j].Latitude / 1000000, forma.Coordenadas[j].Longitude / 1000000);
                
                pts.push(ptAux);
            }

            var objetoForma = new PoligonoTerminal({
                pontos: pts,
                cor: forma.Cor
            });

            formaobj = new google.maps.Polygon(objetoForma);
            break;
        case 3: // circulo
            var centro = new google.maps.LatLng(forma.CentroLatitude / 1000000, forma.CentroLongitude / 1000000);
            
            var objetoForma = new CirculoTerminal({
                centro: centro,
                raio: forma.Raio,
                cor: forma.Cor
            });
            formaobj = new google.maps.Circle(CriarCirculo(objetoForma));
            break;
        case 2: // polilinha
            // a princípio não deve haver polilinhas como terminais...
            break;
        default: // sem forma identificada
            // não deve haver polilinhas sem tipos
            break;
    }
    if (formaobj != null) {

        formaobj.setMap(this.Mapa);
        formaobj.Descricao = forma.Descricao;
        formaobj.Codigo = forma.Codigo;

        this.Terminais.push(formaobj);
        google.maps.event.addListener(formaobj, 'click', function (evt) { mSelf.onClickTerminalPlanejamento(evt, this); });
    }
};

Planejamento.prototype.plotarPlanejamentoPontosControle = function (pontoControle){
    switch (pontoControle.Tipo) {
        case 1: // circulo
            var centro = new google.maps.LatLng(pontoControle.PontoControleLatitude / 1000000, pontoControle.PontoControleLongitude / 1000000);

            

            var objetoForma = new CirculoTerminal({
                centro: centro,
                raio: pontoControle.PontoControleRaio,
                cor: "#000"
            });
            forma = new google.maps.Circle(CriarCirculo(objetoForma));
            break;
        case 3: // polilinha
            // a princípio não deve haver polilinhas como terminais...
            break;
        default: // sem forma identificada
            // não deve haver polilinhas sem tipos
            break;
    }
    if (forma != null) {
        forma.setMap(this.Mapa);

        this.PontosControle.push(forma);
    }
};

function Poligono() {
    this.clickable = true;      // boolean Indicates whether this Polygon handles mouse events. Defaults to true.
    this.editable = true;       // boolean If set to true, the user can edit this shape by dragging the control points
    //                                     shown at the vertices and on each segment. Defaults to false.
    this.fillColor = "";        // string The fill color. All CSS3 colors are supported except for extended named colors.
    this.fillOpacity = 0;       // number The fill opacity between 0.0 and 1.0
    this.geodesic = true;       // boolean When true, render each edge as a geodesic (a segment of a "great circle").
    //                                     A geodesic is the shortest path between two points along the surface of the Earth.
    //                                     When false, render each edge as a straight line on screen. Defaults to false.
    this.map = true;            // Map Map on which to display Polygon.
    this.paths = [];            // MVCArray.<MVCArray.<LatLng>>|MVCArray.<LatLng>|Array.<Array.<LatLng>>|Array.<LatLng>
    //                                     The ordered sequence of coordinates that designates a closed loop. Unlike polylines,
    //                                     a polygon may consist of one or more paths. As a result, the paths property may specify
    //                                     one or more arrays of LatLng coordinates. Paths are closed automatically;
    //                                     do not repeat the first vertex of the path as the last vertex.
    //                                     Simple polygons may be defined using a single array of LatLngs.
    //                                     More complex polygons may specify an array of arrays.
    //                                     Any simple arrays are converted into MVCArrays.
    //                                     Inserting or removing LatLngs from the MVCArray will automatically update the polygon on the map.
    this.strokeColor = true;    // string The stroke color. All CSS3 colors are supported except for extended named colors.
    this.strokeOpacity = 0;     // number The stroke opacity between 0.0 and 1.0
    this.strokePosition = {};   // StrokePosition The stroke position. Defaults to CENTER. This property is not supported
    //                                     on Internet Explorer 8 and earlier.
    this.strokeWeight = 0;      // number The stroke width in pixels.
    this.visible = true;        // boolean Whether this polygon is visible on the map. Defaults to true.
    this.zIndex = 0;            // number The zIndex compared to other polys.
}

function PoligonoTerminal(o) {
    this.fillOpacity = 0.4;
    this.fillColor = "#FF0000";
    this.strokeOpacity = 1.0;
    this.strokeWeight = 1.0;
    this.zIndex = 1;
    this.paths = o.pontos;
}

PoligonoTerminal.prototype = Poligono;


function Circulo() {
    this.center = {}          // LatLng The center
    this.clickable = true;    // boolean Indicates whether this Circle handles mouse events. Defaults to true.
    this.editable = true;     // boolean If set to true, the user can edit this circle by dragging the control points
    //                                    shown at the center and around the circumference of the circle. Defaults to false.
    this.fillColor = "#111";      // string The fill color. All CSS3 colors are supported except for extended named colors.
    this.fillOpacity = 0;     // number The fill opacity between 0.0 and 1.0
    this.map = {};            // Map Map on which to display Circle.
    this.radius = 0;          // number The radius in meters on the Earth's surface
    this.strokeColor = "";    // string The stroke color. All CSS3 colors are supported except for extended named colors.
    this.strokeOpacity = 0;   // number The stroke opacity between 0.0 and 1.0
    this.strokePosition = {}; // StrokePosition The stroke position. Defaults to CENTER.
    //                                    This property is not supported on Internet Explorer 8 and earlier.
    this.strokeWeight = 0;    // number The stroke width in pixels.
    this.visible = true       // boolean Whether this circle is visible on the map. Defaults to true.
    this.zIndex = 0;          // number The zIndex compared to other polys.
}

function CirculoTerminal(o) {
    this.clickable = true;
    this.fillOpacity = 0.4;
    this.strokeColor = o.cor;
    this.strokeOpacity = 1.0;
    this.strokeWeight = 2.0;
    this.zIndex = 1;
    this.center = o.centro;
    this.radius = o.raio;
}
CirculoTerminal.prototype = Circulo;

function PolilinhaPlanejamentoVeiculo(o) {
    this.map = o.mapa;
    this.path = o.pontos;
    this.strokeColor = o.cor;
    this.strokeOpacity = 0;
    this.strokeWeight = 10;
    this.icons = [{
        icon: o.lineSymbol,
        offset: '100%',
        repeat: '10px'
    }];
    this.zIndex = 0;
}
PolilinhaPlanejamentoVeiculo.prototype = PolilinhaOpcoes;

function PolilinhaOpcoes() {
    this.clickable = true; // boolean Indicates whether this Polyline handles mouse events. Defaults to true.
    this.editable = false; // boolean If set to true, the user can edit this shape by dragging the control points
    //                                shown at the vertices and on each segment. Defaults to false.
    this.geodesic = false; // boolean When true, render each edge as a geodesic (a segment of a "great circle").
    //                                A geodesic is the shortest path between two points along the surface of the Earth.
    //                                When false, render each edge as a straight line on screen. Defaults to false.
    this.icons = [];        // Array.<IconSequence> The icons to be rendered along the polyline.
    this.map = {};          // Map Map on which to display Polyline.
    this.path = [];         // MVCArray.<LatLng>|Array.<LatLng> The ordered sequence of coordinates of the Polyline.
    //                                This path may be specified using either a simple array of LatLngs, or an MVCArray of LatLngs.
    //                                Note that if you pass a simple array, it will be converted to an MVCArray Inserting or removing
    //                                LatLngs in the MVCArray will automatically update the polyline on the map.
    this.strokeColor = "";  // string The stroke color. All CSS3 colors are supported except for extended named colors.
    this.strokeOpacity = 0; // number The stroke opacity between 0.0 and 1.0.
    this.strokeWeight = 0;  // number The stroke width in pixels.
    this.visible = true;    // boolean Whether this polyline is visible on the map. Defaults to true.
    this.zIndex = 0;     // number The zIndex compared to other polys.
}

function CriarPolilinha(options) {
    return new google.maps.Polyline(options);
}


Planejamento.prototype.ClickPolilinhaPlanejamento = function (event, polilyne) {
    var mSelf = this;
    if (mSelf.InfoWindow == null) {
        mSelf.InfoWindow = new google.maps.InfoWindow();
    }

    mSelf.CriarElementosPopupMap(mSelf.DescricaoLinha, event.latLng, polilyne.Codigo);
}

Planejamento.prototype.CriarElementosPopupMap = function (titulo, posicao, codigoenlace) {
    var mSelf = this;
    var conteudo = "<strong>" + titulo + "</strong><br>";
    for (var i in mSelf.Enlaces) {
        if (mSelf.Enlaces[i].Codigo == codigoenlace) {
            conteudo += "<strong>" + mSelf.Enlaces[i].Descricao + "</strong><br>";
        } else {
            conteudo += mSelf.Enlaces[i].Descricao + "<br>";
        }
    }
    mSelf.InfoWindow.setContent(conteudo);
    mSelf.InfoWindow.setPosition(posicao);
    mSelf.InfoWindow.open(mSelf.Mapa);
}

//function clickNoMapa(evt) {
//    for (var i in infoWindowPlanejamento) {
//        infoWindowPlanejamento[i].close();
//    }

//    for (var i in infoWindowPlanejamentoTerminais) {
//        infoWindowPlanejamentoTerminais[i].close();
//    }
//}

//function ocultarInfoWindowLinha(linha) {
//    for (var i in arrayInfoWindowLinhas) {
//        if (arrayInfoWindowLinhas[i].key == linha) {
//            arrayInfoWindowLinhas[i].value.close();
//        }
//    }
//}

Planejamento.prototype.onClickTerminalPlanejamento = function(evt, terminal) {
    var mSelf = this;
    if (mSelf.InfoWindowTerminal == null) {
        mSelf.InfoWindowTerminal = new google.maps.InfoWindow();
    }

    mSelf.InfoWindowTerminal.setContent(terminal.Descricao);
    mSelf.InfoWindowTerminal.setPosition(evt.latLng);
    mSelf.InfoWindowTerminal.open(mSelf.Mapa);
}

var lineSymbolplanejamento = {
    path: 'M 0,-0.5 0,0.5',
    strokeWeight: 4,
    strokeOpacity: 1,
    scale: 4
};

