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

/* --------------------------------------------------------------
 *  DATA
 * -------------------------------------------------------------- */
var oStyleMap = new OpenLayers.StyleMap();
var aRoadType = new Array();

// 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: getSelectedRoad
 * Returns the first selected road of the layer olWFSRoads.
 *
 * Returns:
 * {OpenLayers.Feature}
 */
function getSelectedRoad(){
    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){
    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, aszRoadAttr);
        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
 * If at least one road (feature) is selected and the user answers "yes", 
 * delete all selected roads using Strategy.Save.
 */
function beforeRoadsDeleted(event){
    toggleRoadHighlighter("deactivate");

    if(confirm("Delete selected roads ?")){
        oSaveStrategy.save(event.features);
        return true;
    } else {
        return false;
    }

    toggleRoadHighlighter("activate");
}

/**
 * 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: toggleRoadControlElements
 * Enable or disable the draw controls when the olWFSRoads inRange value changes
 */
function toggleEditTools(){
    var szDisplay = oDrawLnCtrl.panel_div.style.display;

    if (olWFSRoads.inRange && szDisplay == "none"){
        oDrawLnCtrl.panel_div.style.display = "";
        oModifyLnCtrl.panel_div.style.display = "";
        oDeleteLnCtrl.panel_div.style.display = "";

        oPanel.activateControl(oModifyLnCtrl);
    } else if (!olWFSRoads.inRange && szDisplay != "none"){
        oDrawLnCtrl.panel_div.style.display = "none";
        oModifyLnCtrl.panel_div.style.display = "none";
        oDeleteLnCtrl.panel_div.style.display = "none";

        if(oDrawLnCtrl.active || oModifyLnCtrl.active || oDeleteLnCtrl.active){
            oPanel.activateControl(oDragPanCtrl);            
        }
    }
}

/**
 * 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}
 *
 * aszAttributes - {Array}         An array attributes names that are in the
 *                                 current html page
 */
function parseFeatureAttributesToForm(oFeature, aszAttributes) {
    for (var i=0, len=aszRoadAttr.length; i<len; i++){
        var szAttribute = aszAttributes[i];
        var szValue = oFeature.attributes[szAttribute];
        if (szValue){
            document.getElementById(szAttribute).value = 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(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, aszAttributes){
    var i, j=0, szAttr;
    var oDate = new Date();
    var aoAttr = oFeature.attributes;
    
    for(i=0; i<aszAttributes.length; i++){
        szAttr = aszAttributes[i];
        szCurrentAttr = aszAllAttributes[j];
        if(szAttr == szCurrentAttr){
            szValue = document.getElementById(szAttr).value;
            aoAttr[szAttr] = szValue;
        }
        else{
            switch(szCurrentAttr)
            {
              case "fnode_":
              case "tnode_":
              case "lpoly_":
              case "rpoly_":
              case "geom_l_len":
                aoAttr[szCurrentAttr] = "0";
                break;    
              case "rol_co_ver":
                aoAttr[szCurrentAttr] = "BDGA1M v1.1";
                break;
              case "rol_da_mod":
                aoAttr[szCurrentAttr] = (oDate.getFullYear()*100 + oDate.getMonth()+1)*100 + oDate.getDate();
                break;
              case "the_geom":
                break;
              default:
            }            
            i--;
        }
        j++;
    }
}

/* --------------------------------------------------------------
 *  POPUP FUNCTIONS
 * -------------------------------------------------------------- */
/**
 * Method: addRoadFormPopup
 * Called when a road feature is selected for modifications.
 *
 * It creates an empty popup displayed at the left or right of the map,
 * depending of center of the selected feature, and moves the hidden <div>
 * that contains the <form>.
 *
 * Parameters:
 * feature - {OpenLayers.Feature}
 */
function addRoadFormPopup(feature) {
    var szHTML = "<div style='font-size:.8em'><h1>Road form</h1>"
               + "<div id='roadFormInPopup'></div>"
               + "</div>";
    var oPopupPos, leftOffset = 45, topOffset = 55, rightOffset=0;

    var oMapExtent = oMap.getExtent();
    var nReso = oMap.getResolution();
    var nMapXCenter = oMap.getExtent().getCenterPixel().x;
    var nFeatureXPos = feature.geometry.getBounds().getCenterPixel().x;
    var bLeft = nFeatureXPos >= nMapXCenter;

    if(bLeft){ // popup appears top-left position
        oPopupPos = new OpenLayers.LonLat(oMapExtent.left,oMapExtent.top);
        oPopupPos.lon += leftOffset * nReso;
    } else { // popup appears top-right position
        oPopupPos = new OpenLayers.LonLat(oMapExtent.right,oMapExtent.top);
        oPopupPos.lon -= rightOffset * nReso;
    }
    oPopupPos.lat -= topOffset * nReso;

    var popup = new OpenLayers.Popup.AnchoredBubble(
        "chicken", 
        oPopupPos,
        new OpenLayers.Size(225,275),
        szHTML,
        null, true, onRoadFormPopupClose);
    feature.popup = popup;
    oMap.addPopup(popup);

    // move roadForm <div> inside popup
    oRoadFormDiv = document.getElementById('roadFormDiv');
    oDiv = document.getElementById('roadFormInPopup');
    oDiv.appendChild(oRoadFormDiv);
}

/**
 * Method: removeRoadFormPopup
 * Move roadForm <div> back to its hidden location, then remove the popup of
 * road feature.  Used when the road feature is selected.
 *
 * Parameters:
 * feature - {OpenLayers.Feature}
 */
function removeRoadFormPopup(feature) {
    // first, move roadForm <div> from popup to hidden <div>
    oRoadFormDiv = document.getElementById('roadFormDiv');
    oDiv = document.getElementById('hiddenRoadFormDiv');
    oDiv.appendChild(oRoadFormDiv);

    oMap.removePopup(feature.popup);
    feature.popup.destroy();
    feature.popup = null;
}

/**
 * Method: onRoadFormPopupClose
 * When a popup is closed, unselect the corresponding feature at the same time.
 *
 * Parameters:
 * evt
 */
function onRoadFormPopupClose(evt) {
    oFeature = getSelectedRoad();
    if (oFeature){
        oModifyLnCtrl.selectControl.unselect(oFeature);
    }
}

// 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();
    }
    addRoadFormPopup(oFeature);

    if(oFeature.state != "Insert"){
        parseFeatureAttributesToForm(oFeature, aszRoadAttr);
    }

    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);
    removeRoadFormPopup(oFeature);
    document.getElementById('roadForm').reset();
    toggleRoadHighlighter('enable');
};
        
function roadFeatureAdded(object){
    var oFeature = object.feature;
    oFeature.state = OpenLayers.State.INSERT;
    oPanel.activateControl(oModifyLnCtrl);
    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("Transaction successfully completed");
};

function showFailureMsg(){
    showMsg("An error occured while operating the transaction");
};

function onBeforeRoadRemoved(object){
    if(oRoadHighlighter.feature == object.feature){
        oRoadHighlighter.resetFeature();
    }
}

