/**
 * File : bdgaRoads.js
 * Contains data and functions for the olWFSRoads layer and its controls
 *
 */

/* --------------------------------------------------------------
 *  DATA
 * -------------------------------------------------------------- */

var oStyleMap = new OpenLayers.StyleMap(), aRoadType = new Array(),
    oRoadFormWindow;

// color when road selected
aRoadTypeSelect = {
  AUT: { strokeColor : "black", strokeWidth : 7 },
  NAT: { strokeColor : "black", strokeWidth : 7 },
  REG: { strokeColor : "black", strokeWidth : 7 },
  COL: { strokeColor : "black", strokeWidth : 7 },
  ACC: { strokeColor : "black", strokeWidth : 7 },
  LOC: { strokeColor : "black", strokeWidth : 7 },
  ACH: { strokeColor : "black", strokeWidth : 7 },
  MRN: { strokeColor : "black", strokeWidth : 7 }
}

// same color as wms
/*
aRoadType = {
  AUT: { text: "Autoroute",       strokeColor:"#eead0e", strokeWidth: 7 },
  NAT: { text: "Nationale",       strokeColor:"#f0e68c", strokeWidth: 5 },
  REG: { text: "Régionale - Reg", strokeColor:"#f0e68c", strokeWidth: 4 },
  COL: { text: "Régionale - Col", strokeColor:"#f0e68c", strokeWidth: 4 },
  ACC: { text: "Locale - Acc",    strokeColor:"#cccccc", strokeWidth: 3 },
  LOC: { text: "Locale - Loc",    strokeColor:"#cccccc", strokeWidth: 3 },
  ACH: { text: "Chemin forestier - Ach",strokeColor:"#cda65a", strokeWidth: 3 },
  MRN: { text: "Chemin forestier - Mrn",strokeColor:"#cda65a", strokeWidth: 3 }
}
*/

// same color as road signs
aRoadType = {
  AUT: { text: "Autoroute", strokeColor:"#284386", strokeWidth: 7 },
  NAT: { text: "Nationale", strokeColor:"#0aa989", strokeWidth: 5 },
  REG: { text: "Régionale - Reg", strokeColor:"#0aa989", strokeWidth: 4 },
  COL: { text: "Régionale - Col", strokeColor:"#0aa989", strokeWidth: 4 },
  ACC: { text: "Locale - Acc",    strokeColor:"#f4a427", strokeWidth: 3 },
  LOC: { text: "Locale - Loc",    strokeColor:"#f4a427", strokeWidth: 3 },
  ACH: { text: "Chemin forestier - Ach",strokeColor:"#cda65a", strokeWidth: 3 },
  MRN: { text: "Chemin forestier - Mrn",strokeColor:"#cda65a", strokeWidth: 3 }
}

oStyleMap.addUniqueValueRules("default", "rol_co_cla", aRoadType);
oStyleMap.addUniqueValueRules("select", "rol_co_cla", aRoadTypeSelect);

rules = [new OpenLayers.Rule({
          symbolizer: {strokeColor:"red",strokeWidth: 2},
                elseFilter: true
            })];
rulesSelect = [new OpenLayers.Rule({
          symbolizer: {strokeColor:"black",strokeWidth: 2},
                elseFilter: true
            })];

oStyleMap.styles["default"].addRules(rules);
oStyleMap.styles["select"].addRules(rulesSelect);

/* --------------------------------------------------------------
 *  FUNCTIONS
 * -------------------------------------------------------------- */

/**
 * Method: toggleDeleteRoads
 * Enable or disable the button 'deleteRoads' depending on the szToggle value
 *
 * Parameters:
 * szToggle - string     Contains the action to do : "enable" or "disable"
 *
 */
function toggleDeleteRoads(szToggle){
    if (szToggle == "enabled" || szToggle == "enable"){
        szToggle = "";
    } else if (szToggle == "disable"){
        szToggle = "disabled";
    }

    if (szToggle == "" || szToggle == "disabled"){
        document.getElementById('deleteRoads').disabled = szToggle;
    } else {
        alert("Error : bad parameter in toggleDeleteRoads function");
    }
}

/**
 * Method: getSelectedRoad
 * Returns the first selected road of the layer olWFSRoads.
 *
 * Returns:
 * {OpenLayers.Feature}
 */
function getSelectedRoad(){
    //return olWFSRoads.getSelectedFeature();
    return oModifyLnCtrl.feature;
}

/**
 * Method: drawRoad 
 * Draw the given feature (road) depending on which type of road is selected
 * on the html element that has the same id than the attribute name of the
 * road that decides its color.
 *
 * Parameters:
 * oFeature - {OpenLayers.Feature} Feature from the vector road layer olWFSRoads
 *
 */
function drawRoad(oFeature, szRoadCla){ // not working anymore
    if (szRoadCla == null){
        szRoadCla = document.getElementById('rol_co_cla').value;
    }
    olWFSRoads.drawFeature(oFeature, aRoadType[szRoadCla]);
}

/**
 * Method: saveRoad 
 * If road attributes of selected feature are valid when user clicks the "save"
 * button, save them and its geometry to the database using a WFS:Insert or
 * WFS:Update POST request.
 * 
 * Can only save one feature at a time using Strategy.Save : the selected one.
 */
function saveRoad() {
    var oFeature = getSelectedRoad();

    if (isValidRoadAttributes(oFeature, aszRoadAttr)){
        //check state, parse attributes, save and unselect current road
        if(oFeature.state != OpenLayers.State.INSERT) {
            oFeature.state = OpenLayers.State.UPDATE;
        }
        parseFormAttributesToFeature(oFeature, aszAllRoadAttr, oRoadForm);
        switch(oFeature.layer.protocol.CLASS_NAME) {
          case "OpenLayers.Protocol.HTTP":
            oFeature.layer.protocol.commit([oFeature]);
/*
, {
                    "update": { callback: onUpdate(response) },
                        "create": { callback: onCreate(response) },
                            "delete": { callback: onDelete(response) }
            });
*/
            break;    
          case "OpenLayers.Protocol.WFS.v1_0_0":
            oSaveStrategy.save([oFeature]);            
            break;
          default:
            alert("not suported");
        }
        oModifyLnCtrl.selectControl.unselect(oFeature);
    }
}

/**
 * Method: beforeRoadsDeleted
 * Triggered by beforefeaturesdeleted event of DeleteFeature control.  It
 * displays a yes/no message box to confirm the user's choice to delete roads.
 *
 * Because the message box is asynchronous, DeleteFeature.deleteFeatures is
 * called in silence mode, i.e. it doesn't trigger beforefeaturedeleted and
 * directly triggers deletefeatures.
 */
function beforeRoadsDeleted(object){
    toggleRoadHighlighter("deactivate");

    Ext.Msg.confirm('Delete selected roads', 
                    'Are you sure you want to delete the selected roads ?', 
                    function(btn){
                        if (btn == 'yes'){
                            oDeleteLnCtrl.deleteFeatures({
                                silent: true
                            });
                        }
                        toggleRoadHighlighter("activate");
                    });
    return false; 
}

/**
 * Method: deleteRoads
 * Delete all selected roads using Strategy.Save.
 */
function deleteRoads(event){
    oSaveStrategy.save(event.features);
}

/**
 * Method: toggleDrawControl
 * Using an array of controls, enable the selected one, disable others.
 *
 * Parameters:
 * element - selected html element representing the control activated.
 */
function toggleDrawControl(element) {
    for (key in oDrawControls) {
        var oDrawControl = oDrawControls[key];
        if (element.value == key && element.checked) {
            oDrawControl.activate();
        } else {
            oDrawControl.deactivate();
        }
    }
}

/**
 * Method: updtateModifyMode
 * Enable the different possible modify modes like reshape, rotate, resize
 * and drag for the oDrawControls (for roads).  If the correct checkbox is
 * checked, then it enables the mode.
 */
function updateModifyMode() {
    // reset modification mode
    oDrawControls.modify.mode = OpenLayers.Control.ModifyFeature.RESHAPE;

    var rotate = document.getElementById("rotate").checked;
    if(rotate) {
        oDrawControls.modify.mode |= OpenLayers.Control.ModifyFeature.ROTATE;
    }

    var resize = document.getElementById("resize").checked;
    if(resize) {
        oDrawControls.modify.mode |= OpenLayers.Control.ModifyFeature.RESIZE;
    }

    var drag = document.getElementById("drag").checked;
    if(drag) {
        oDrawControls.modify.mode |= OpenLayers.Control.ModifyFeature.DRAG;
    }

    // disable reshape mode if at least one of modes rotate, resize,
    //drag is enabled
    if (rotate || resize || drag) {
        oDrawControls.modify.mode &= ~OpenLayers.Control.ModifyFeature.RESHAPE;
    }
}

/**
 * Method: setRoadAttributes
 * Fill the aszRoadAttr array with names of existing html elements that
 * have the same id than an attribute name.
 * Fill the aszAllRoadAttr array with all attribute names found.
 *
 * Parameters:
 * response - {GML} response of the DescribeFeatureType request
 */
function setRoadAttributes(response) {
    oWFSDescFeatType = new OpenLayers.Format.WFSDescribeFeatureType_1_0_0();
    oFeatures = oWFSDescFeatType.read(response.responseText);

    var aItems = new Array();
    aItems = oFeatures[0].items;
    var j=0;
    
    for (i=0; i<aItems.length; i++){
        aszAllRoadAttr[i] = aItems[i].name;
        if (document.getElementById(aItems[i].name)){
            aszRoadAttr[j] = aItems[i].name;
            j++;
        }
    }
}

/**
 * Method: toggleEditTools
 * Enable or disable the draw controls when the olWFSRoads inRange value changes
 */
function toggleEditTools(){
    var bHidden = oDrawLnButton.hidden;

    if (olWFSRoads.inRange && bHidden){
        oDrawLnButton.show();
        oModifyLnButton.show();
        oDeleteLnButton.show();
    } else if (!olWFSRoads.inRange && !bHidden){
        oDrawLnButton.hide();
        oModifyLnButton.hide();
        oDeleteLnButton.hide();

        oDragPanButton.toggle();
        toggleRoadHighlighter('disable');
    }
}

/**
 * Method: toggleRoadHighlighter
 * Enable or disable oRoadHighlighter depending on the szToggle value
 *
 * Parameters:
 * szToggle - string     Contains the action to do : "enable" or "disable"
 *
 */
function toggleRoadHighlighter( szToggle ) {
    if (szToggle == "enabled" || szToggle == "enable" ||
        szToggle == "activate" || szToggle == ""){
        if (!oRoadHighlighter.active){
            oRoadHighlighter.activate();
        }
    } else if (szToggle == "disable" || szToggle == "disabled" ||
             szToggle == "deactivate"){
        if (oRoadHighlighter.active){
            oRoadHighlighter.deactivate();
        }
    } else { 
        alert("Error : bad parameter in toggleRoadHighlighter function");
    }
}

/**
 * Method: parseFeatureAttributesToForm
 * Parse each attributes value of feature in the corresponding html element
 * that as the same id as the attribute's name
 *
 * Parameters:
 * oFeature - {OpenLayers.Feature}
 *
 * oForm - {Ext.FormPanel} The road form that contains inputable
 *                             elements
 */
function parseFeatureAttributesToForm(oFeature, oForm){
    var aoElements, nElements;
    aoElements = oForm.items.items;
    nElements = aoElements.length;

    for (var i=0; i<nElements; i++){
        var oElement = aoElements[i];
        var szAttribute = oElement.getId();
        var szValue = oFeature.attributes[szAttribute];
        oElement.setValue(szValue);
    }
}

/**
 * Method: isValidRoadAttributes
 * Validate each kind of road attributes value.
 *
 * Parameters:
 * oFeature - {OpenLayers.Feature}
 *
 * aszAttributes - {Array}         An array attributes names that are in the
 *                                 current html page
 * Returns:
 * bValid - boolean                False if one of the attribute's value is
 *                                 invalid
 */
function isValidRoadAttributes(oFeature, aszAttributes){
    var bValid = true;
    var szErrMsg = "invalid ";

    for(i=0; i<aszAttributes.length && bValid; i++){
        szAttribute = aszAttributes[i];
        switch(szAttribute){
          case "length":
            szValue = document.getElementById(szAttribute).value;
            bValid = szValue.match(/^\d{1,19}$/);
            break;
          case "rol_va_lon":
            szValue = document.getElementById(szAttribute).value;
            bValid = szValue.match(/^\d{1,10}$/);
            break;
          case "rol_no_rou":
            szValue = document.getElementById(szAttribute).value;
            bValid = szValue.match(/^\w{1,5}$/);
            break;
          default:
        }

        if (!bValid){
            szErrMsg += szAttribute;
            showMsg("Error", szErrMsg);
        }
    }

    return bValid;
}

/**
 * Method: parseFormAttributesToFeature
 * Parse each attributes value from an HTML form to a feature.  Each attribute 
 * names share the id of an html element.
 *
 * Parameters:
 * oFeature - {OpenLayers.Feature}
 *
 * aszAttributes - {Array}         Current feature attributes names that have
 *                                 a existing html element that has an id
 *                                 equal to an attribute name.
 * aszAttributes - {Array}         All attributes of current road feature 
 */
function parseFormAttributesToFeature(
    oFeature, aszAllAttributes, oRoadForm){
    var szAttr, szValue, oDate = new Date(), aoAttr = oFeature.attributes,
        aoItems = oRoadForm.items, nIdx, oElement;

    for(var i=0, nAttributes = aszAllAttributes.length; i<nAttributes; i++){
        szAttr = aszAllAttributes[i];
        if (aoItems.containsKey(szAttr)){
            nIdx = aoItems.indexOfKey(szAttr);
            oElement = aoItems.get(nIdx);
            szValue = oElement.getValue();
            aoAttr[szAttr] = szValue;
        } else {
            switch(szAttr) {
              case "fnode_":
              case "tnode_":
              case "lpoly_":
              case "rpoly_":
              case "geom_l_len":
                aoAttr[szAttr] = "0";
                break;    
              case "rol_co_ver":
                aoAttr[szAttr] = "BDGA1M v1.1";
                break;
              case "rol_da_mod":
                aoAttr[szAttr] = (oDate.getFullYear()*100 + oDate.getMonth()+1)*100 + oDate.getDate();
                break;
              case "the_geom":
                break;
              default:
            }
        }
    }
}

/**
 * Method: showRoadFormWindow
 * Called when a road feature is selected for modifications.
 *
 * It show the oRoadFormWindow on the left or on the right of the map
 * depending of center of the selected feature.
 *
 * Parameters:
 * feature - {OpenLayers.Feature}
 */
function showRoadFormWindow(feature){
    var nMapXCenter, nFeatureXPos, nWinXPos, nWinYPos,
        nXOffset = 45, nYOffset = 55;

    // calculate where (left or right) the popup will appear
    nMapXCenter = oMap.getExtent().getCenterPixel().x;
    nFeatureXPos = feature.geometry.getBounds().getCenterPixel().x;
    if (nFeatureXPos >= nMapXCenter) { // window appears to the left
        nWinXPos = oMapComponent.x + nXOffset;
        nWinYPos = oMapComponent.y + nYOffset;
    } else { // window appears to the right
        nWinXPos = oMapComponent.x + oMap.getSize().w - oRoadFormWindow.width;
        nWinYPos = oMapComponent.y + nYOffset;
    }
    oRoadFormWindow.setPosition(nWinXPos,nWinYPos);
    oRoadFormWindow.show();
}

// MODIFICATION AND DRAW FUNCTIONS

function onRoadModificationStart(object) {
    var oFeature;
    if (object.geometry){
        oFeature = object;
    } else {
        oFeature = object.feature;
    }
    OpenLayers.Console.log("start modifying", oFeature.id);

    if(oRoadHighlighter.feature){
        oRoadHighlighter.resetFeature();
    }
    showRoadFormWindow(oFeature);

    if(oFeature.state != "Insert"){
        parseFeatureAttributesToForm(oFeature, oRoadForm);
    }
    toggleRoadHighlighter('disable');
};

function onRoadModification(object) {
    var oFeature;
    if (object.geometry){
        oFeature = object;
    } else {
        oFeature = object.feature;
    }
    OpenLayers.Console.log("modified", oFeature.id);
};

function onRoadModificationEnd(object) {
    var oFeature;
    if (object.geometry){
        oFeature = object;
    } else {
        oFeature = object.feature;
    }
    OpenLayers.Console.log("end modifying", oFeature.id);
    oRoadFormWindow.hide();
    oRoadForm.getForm().reset();
    toggleRoadHighlighter('enable');
};
        
function roadFeatureAdded(object){
    var oFeature = object.feature;
    //oFeature.layer.eraseFeatures([oFeature]);
    // cast to multilinestring
/*
  oFeature.geometry = new OpenLayers.Geometry.MultiLineString(
  oFeature.geometry
  );
*/
    oFeature.state = OpenLayers.State.INSERT;
    oModifyLnButton.toggle();
    oModifyLnCtrl.selectControl.select(oFeature);
}

function onModifyLnCtrlActivated(){
    toggleRoadHighlighter('enable');
}

function onModifyLnCtrlDeactivated(){
    if (!oDeleteLnCtrl.active){
        toggleRoadHighlighter('disable');
    }
}

function onDeleteLnCtrlActivated(){
    toggleRoadHighlighter('enable');
}

function onDeleteLnCtrlDeactivated(){
    if (!oModifyLnCtrl.active){
        toggleRoadHighlighter('disable');
    }
}

function showSuccessMsg(){
    showMsg("Success", "Transaction successfully completed");
};

function showFailMsg(){
    showMsg("Error", "An error occured while operating the transaction.");
};

function onRoadClassSelected(combo, record){
    var szRoadClass = record.get('class');
    drawRoad(getSelectedRoad(), szRoadClass);
}

function onFeatureHLSet(object) {
    var oFeature, nMapXCenter, nFeatureXPos, nWinXPos, nWinYPos, szHTML, 
        nLeftOffset, nTopOffset, nRightOffset;
    if (object.geometry){
        oFeature = object;
    } else {
        oFeature = object.feature;
    }

    // feature attributes parsing in html
    szHTML = "<div style='height:260px'><table border='0'>";
    if (!oFeature.cluster){
        aszAttributes = oFeature.attributes;
        for(var key in aszAttributes){
            szHTML += "<tr><td><div style='font-size:0.7em; font-color:red;'>"
                + key + "</div></td><td><div style='font-size:0.7em'> : "
                + aszAttributes[key] + "</div></td></tr>";
        }
    }
    szHTML +="</table></div>";

    var oPanel = new Ext.Panel({
        region    : 'center',
        items     : [{
            html : szHTML
        }]
    });

    oRoadInfoWindow.insert(0, oPanel);

    nLeftOffset = oRoadHighlighter.popupOffset.left;
    nTopOffset = oRoadHighlighter.popupOffset.top + 50;
    nRightOffset = oRoadHighlighter.popupOffset.right;

    // calculate where (left or right) the popup will appear
    nMapXCenter = oMap.getExtent().getCenterPixel().x;
    nFeatureXPos = oFeature.geometry.getBounds().getCenterPixel().x;
    if (nFeatureXPos >= nMapXCenter) { // window appears to the left
        nWinXPos = oMapComponent.x + nLeftOffset;
    } else { // window appears to the right
        nWinXPos = oMapComponent.x + oMap.getSize().w - oRoadFormWindow.width
                                   - nRightOffset;
    }
    nWinYPos = oMapComponent.y + nTopOffset;

    oRoadInfoWindow.setPosition(nWinXPos,nWinYPos);
    oRoadInfoWindow.show();
}

function onFeatureHLReset(object) {
    oRoadInfoWindow.remove(oRoadInfoWindow.items.items[0]);
    oRoadInfoWindow.hide();
}

