        //KML objects v1.0 Updated: 20080826 by Isaac Yong
        /*
            myObj.addLayer=addLayer;
            myObj.addLayers=addLayers;
            myObj.enableLayer=enableLayer;
            myObj.enableLayers=enableLayers;
            myObj.refresh=refresh;
            myObj.refreshAll=refreshAll;
            myObj.getLayer=getLayer;
            myObj.disableLayer=disableLayer;
            myObj.disableLayers=disableLayers;
            myObj.getCtrl=getCtrl;
            myObj.createTopMostLayer=createTopMostLayer;
            myObj.setTopMostLayer=setTopMostLayer;
            myObj.removeLayer=removeLayer;
            myObj.containsLayerKey=containsLayerKey;
                    
        sample code:
            objMyKMLs = new objKMLs();
            objMyKMLs.addLayer("seleter_route", "kml/test_bus_route_morning.kml", true, true);
            objMyKMLs.enableLayer("seleter_route");        
        */        
        
        function objKMLs(){
            var myObj=new Object();
            var htbKMLLayers = new Hashtable();
            var htbKMLActLayers = new Hashtable();
            var htbKMLCtrls = new Hashtable();
            var topMostLayer;

            //object for storing raw KML data/setting
            function objKML(strId, strURL, boolRefresh, boolBalloon){
                  var myObj=new Object();
                  myObj.id    = strId;
                  myObj.url   = strURL;              
                  myObj.refresh = boolRefresh;              
                  myObj.balloon  = boolBalloon;
                  return myObj;
            }
            //end of object for storing raw KML data/setting

            //function addLayer()
            function addLayer(strId, strURL, boolRefresh, boolBalloon){
                htbKMLLayers.put(strId,new objKML(strId, strURL, boolRefresh,boolBalloon));
            }
            
            function addLayers(arrInput){
                for(var i = 0; i<arrInput.length;i++){
                    htbKMLLayers.put(arrInput[i][0],objKML(arrInput[i][0], arrInput[i][1], arrInput[i][2], arrInput[i][3]));                    
                }    
            }
            
            function enableLayer(strId){
                var rtnLayer;
                if(!htbKMLActLayers.containsKey(strId)){
                    var objKML = htbKMLLayers.get(strId);
                    var rtnLayer = new OpenLayers.Layer.GML(objKML.id, objKML.url, 
                       {
                        format: OpenLayers.Format.KML, 
                        formatOptions: {
                          extractStyles: true, 
                          extractAttributes: true
                        }
                       });
                    
                    map.addLayer(rtnLayer);
                       
                    htbKMLActLayers.put(strId, rtnLayer);
                    
                    if(objKML.balloon){
                        //alert("testing");
                        rtnLayer.preFeatureInsert=function (feature){
                            feature.style.cursor='pointer';
                            if ((feature.attributes.styleUrl) == "#PnRIcon"){
                                feature.style.graphicHeight = 20;
                                feature.style.graphicWidth = 60;
                            }
                    }
                        htbKMLCtrls.put(strId, addSelectControl(rtnLayer));
                    }else {
                        rtnLayer.preFeatureInsert=function (feature){
                            if ((feature.attributes.styleUrl) == "#taxiIcon"){
                                feature.style.graphicHeight = 25;
                                feature.style.graphicWidth = 25;
                            }
                        }
                    }
                    
                    //rtnLayer = kmlLayer;
                    if(topMostLayer != null)
                        setTopMostLayer();
                        //map.setLayerIndex(rtnLayer);
                } else{
                    rtnLayer = htbKMLActLayers.get(strId);
                    rtnLayer.setVisibility(true);                    
                    }
                    
                return rtnLayer;
            }
            
            function addSelectControl(vectorLayer){
                var selectControl = new OpenLayers.Control.SelectFeature(vectorLayer,
                            {onSelect: onFeatureSelect, onUnselect: onFeatureUnselect});
                map.addControl(selectControl);
                selectControl.activate();
                
                return selectControl;
            }
            
            function enableLayers(arrId){
                var kmlLayers = new Array();
                for(var i = 0; i<arrId.length;i++){
                    var kmlLayer = enableLayer(arrId[i]);
                    kmlLayers[i] = kmlLayer; 
                }
                
                return kmlLayers;
            }
            
            function disableLayer(strId){
                if(htbKMLActLayers.containsKey(strId)){
                    (htbKMLActLayers.get(strId)).setVisibility(false);
                }
            }
            
            function disableLayers(arrId){
                for(var i = 0; i<arrId.length;i++){
                    disableLayer(arrId[i]);
                }
            }
            
            function refresh(strId){
                var objKML = htbKMLLayers.get(strId);
                (htbKMLActLayers.get(strId)).setUrl(objKML.url);                                
            }
            
            function refreshAll(){
                var arrActKeys = htbKMLActLayers.keys();
                for(var i = 0; i<arrActKeys.length;i++){
                    var objKML = htbKMLLayers.get(arrActKeys[i]);
                    if(objKML.refresh)
                        refresh(arrActKeys[i]);
                }
            }

            function getLayer(strId){
                return htbKMLActLayers.get(strId);
            }
            
            function getCtrl(strId){
                return htbKMLCtrls.get(strId);
            }
            
            function createTopMostLayer(strId){
                htbKMLLayers.put(strId,new objKML(strId, "", false,true));
                topMostLayer = new OpenLayers.Layer.Vector(strId);
                topMostLayer.preFeatureInsert = myStyle;
                
                function myStyle(feature){
                    //feature.style = OpenLayers.Util.extend({'cursor':'pointer'}, feature.style);
                    feature.style.cursor = 'pointer';
                    if((feature.attributes.styleUrl).indexOf("mrt") != -1 || (feature.attributes.styleUrl).indexOf("lrt") != -1){
                        feature.style.graphicHeight = 30;
                        feature.style.graphicWidth = 130;
                    } else if ((feature.attributes.styleUrl) == "#busStopIcon"){
                        feature.style.graphicHeight = 25;
                        feature.style.graphicWidth = 25;                    
                    } else if ((feature.attributes.styleUrl) == "#busStopMixIcon"){
                        feature.style.graphicHeight = 25;
                        feature.style.graphicWidth = 25;
                    } else if ((feature.attributes.styleUrl) == "#busStopPremiumIcon"){
                        feature.style.cursor = '';
                        feature.style.graphicHeight = 5;
                        feature.style.graphicWidth = 5;
                    } else if ((feature.attributes.styleUrl) == "#PnRIcon"){
                        feature.style.graphicHeight = 20;
                        feature.style.graphicWidth = 60;
                    } else if ((feature.attributes.styleUrl) == "#busStopMixWArrivalIcon"){
                        feature.style.graphicHeight = 31;
                        feature.style.graphicWidth = 31;
                    } else if ((feature.attributes.styleUrl) == "#busStopWArrivalIcon"){
                        feature.style.graphicHeight = 31;
                        feature.style.graphicWidth = 31;
                    }
                }
                map.addLayer(topMostLayer);
                htbKMLCtrls.put(strId, addSelectControl(topMostLayer));
                htbKMLActLayers.put(strId,topMostLayer);
                setTopMostLayer();
                return topMostLayer;
            }
            
            function setTopMostLayer(objLayer){
                var rtn;
                if(objLayer == null || objLayer == ""){                
                    rtn = map.setLayerIndex(topMostLayer, map.getNumLayers()-1);                    
                    map.setLayerZIndex(topMostLayer,map.getNumLayers()-1);  
                    }
                else {
                    rtn = map.setLayerIndex(objLayer, map.getNumLayers()-1);
                    map.setLayerZIndex(topMostLayer,map.getNumLayers()-1); 
                }
                return rtn;
            }
            
            function removeLayer(strId){
                if(htbKMLActLayers.containsKey(strId)){
                    (htbKMLActLayers.get(strId)).destroy();
                    map.removeLayer(htbKMLActLayers.get(strId),false);
                    htbKMLActLayers.remove(strId);
                }
            }
            
            function containsLayerKey(strId){
                return htbKMLLayers.containsKey(strId);
            }
            
            //general functions for balloon popups features
    	      function onPopupClose(evt) {
                var arrActKeys = htbKMLActLayers.keys();
                for(var i = 0; i<arrActKeys.length;i++){
                    var objKML = htbKMLLayers.get(arrActKeys[i]);
                    if(objKML.balloon)
                        (getCtrl(arrActKeys[i])).unselectAll();
                        //(getCtrl(arrActKeys[i])).unselect(selectedFeature); 
                        //improvement needed to unselect particular selectedFeature;
                }
            }
            
            function onFeatureSelect(feature) {
            
                if(feature.attributes.description!="" && feature.attributes.name!="" &&
                    typeof(feature.attributes.description)!="undefined" && typeof(feature.attributes.name)!="undefined"){
                    selectedFeature = feature;
                    if(getInternetExplorerVersion()!=-1){
                        //alert("IE 100 ori");
                        popup = new OpenLayers.Popup.FramedCloud("chicken", 
                                                 feature.geometry.getBounds().getCenterLonLat(),
                                                 new OpenLayers.Size(400,200),
                                                 "<h2>"+feature.attributes.name + "</h2>" + feature.attributes.description,
                                                 null, true, onPopupClose);                                
                    }
                    else{
                        //alert("Non-IE");
                        popup = new OpenLayers.Popup.FramedCloud("chicken",
                                                 feature.geometry.getBounds().getCenterLonLat(),
                                                 new OpenLayers.Size(400,200),
                                                 "<span id=\"myPopupName\">"+feature.attributes.name + "</span>"
                                                 + "<span id=\"myPopupDesc\">" + feature.attributes.description + "</span>",
                                                 null, true, onPopupClose);
                    }
                } else {
                    popup = new OpenLayers.Popup.FramedCloud("chicken",
                                             feature.geometry.getBounds().getCenterLonLat(),
                                             new OpenLayers.Size(400,200),
                                             "<span id=\"myPopupName\">"+feature.attributes.name + "</span>"
                                             + "<span id=\"myPopupDesc\">" + feature.attributes.description + "</span>",
                                             null, true, onPopupClose);
                    popup.hide(true);
                }
                feature.popup = popup;
                map.addPopup(popup);
            }
            
            function onFeatureUnselect(feature) {
                map.removePopup(feature.popup);
                feature.popup.destroy();
                feature.popup = null;
            }
            
            function getInternetExplorerVersion()
            // Returns the version of Internet Explorer or a -1
            // (indicating the use of another browser).
            {
              var rv = -1; // Return value assumes failure.
              if (navigator.appName == 'Microsoft Internet Explorer')
              {
                var ua = navigator.userAgent;
                var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
                if (re.exec(ua) != null)
                  rv = parseFloat( RegExp.$1 );
              }
              return rv;
            }
            //end of general functions for balloon popups features

            //-------------------------------------------//
            myObj.addLayer=addLayer;
            myObj.addLayers=addLayers;
            myObj.enableLayer=enableLayer;
            myObj.enableLayers=enableLayers;
            myObj.refresh=refresh;
            myObj.refreshAll=refreshAll;
            myObj.getLayer=getLayer;
            myObj.disableLayer=disableLayer;
            myObj.disableLayers=disableLayers;
            myObj.getCtrl=getCtrl;
            myObj.createTopMostLayer=createTopMostLayer;
            myObj.setTopMostLayer=setTopMostLayer;
            myObj.removeLayer=removeLayer;
            myObj.containsLayerKey=containsLayerKey;
            //myObj.objMyImg=objMyImg;
            
            return myObj;        
        }
        //End of KML objects by Isaac Yong
