// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
// This work is free. You can redistribute it and/or modify it
// under the terms of the WTFPL, Version 2
// For more information see LICENSE.txt or http://www.wtfpl.net/
//
// For more information, the home page:
// http://pieroxy.net/blog/pages/lz-string/testing.html
//
// LZ-based compression algorithm, version 1.3.3
var LZString = {
  
  
  // private property
  _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  _f : String.fromCharCode,
  
  compressToBase64 : function (input) {
    if (input == null) return "";
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;
    
    input = LZString.compress(input);
    
    while (i < input.length*2) {
      
      if (i%2==0) {
        chr1 = input.charCodeAt(i/2) >> 8;
        chr2 = input.charCodeAt(i/2) & 255;
        if (i/2+1 < input.length) 
          chr3 = input.charCodeAt(i/2+1) >> 8;
        else 
          chr3 = NaN;
      } else {
        chr1 = input.charCodeAt((i-1)/2) & 255;
        if ((i+1)/2 < input.length) {
          chr2 = input.charCodeAt((i+1)/2) >> 8;
          chr3 = input.charCodeAt((i+1)/2) & 255;
        } else 
          chr2=chr3=NaN;
      }
      i+=3;
      
      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;
      
      if (isNaN(chr2)) {
        enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
        enc4 = 64;
      }
      
      output = output +
        LZString._keyStr.charAt(enc1) + LZString._keyStr.charAt(enc2) +
          LZString._keyStr.charAt(enc3) + LZString._keyStr.charAt(enc4);
      
    }
    
    return output;
  },
  
  decompressFromBase64 : function (input) {
    if (input == null) return "";
    var output = "",
        ol = 0, 
        output_,
        chr1, chr2, chr3,
        enc1, enc2, enc3, enc4,
        i = 0, f=LZString._f;
    
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
    
    while (i < input.length) {
      
      enc1 = LZString._keyStr.indexOf(input.charAt(i++));
      enc2 = LZString._keyStr.indexOf(input.charAt(i++));
      enc3 = LZString._keyStr.indexOf(input.charAt(i++));
      enc4 = LZString._keyStr.indexOf(input.charAt(i++));
      
      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;
      
      if (ol%2==0) {
        output_ = chr1 << 8;
        
        if (enc3 != 64) {
          output += f(output_ | chr2);
        }
        if (enc4 != 64) {
          output_ = chr3 << 8;
        }
      } else {
        output = output + f(output_ | chr1);
        
        if (enc3 != 64) {
          output_ = chr2 << 8;
        }
        if (enc4 != 64) {
          output += f(output_ | chr3);
        }
      }
      ol+=3;
    }
    
    return LZString.decompress(output);
    
  },

  compressToUTF16 : function (input) {
    if (input == null) return "";
    var output = "",
        i,c,
        current,
        status = 0,
        f = LZString._f;
    
    input = LZString.compress(input);
    
    for (i=0 ; i<input.length ; i++) {
      c = input.charCodeAt(i);
      switch (status++) {
        case 0:
          output += f((c >> 1)+32);
          current = (c & 1) << 14;
          break;
        case 1:
          output += f((current + (c >> 2))+32);
          current = (c & 3) << 13;
          break;
        case 2:
          output += f((current + (c >> 3))+32);
          current = (c & 7) << 12;
          break;
        case 3:
          output += f((current + (c >> 4))+32);
          current = (c & 15) << 11;
          break;
        case 4:
          output += f((current + (c >> 5))+32);
          current = (c & 31) << 10;
          break;
        case 5:
          output += f((current + (c >> 6))+32);
          current = (c & 63) << 9;
          break;
        case 6:
          output += f((current + (c >> 7))+32);
          current = (c & 127) << 8;
          break;
        case 7:
          output += f((current + (c >> 8))+32);
          current = (c & 255) << 7;
          break;
        case 8:
          output += f((current + (c >> 9))+32);
          current = (c & 511) << 6;
          break;
        case 9:
          output += f((current + (c >> 10))+32);
          current = (c & 1023) << 5;
          break;
        case 10:
          output += f((current + (c >> 11))+32);
          current = (c & 2047) << 4;
          break;
        case 11:
          output += f((current + (c >> 12))+32);
          current = (c & 4095) << 3;
          break;
        case 12:
          output += f((current + (c >> 13))+32);
          current = (c & 8191) << 2;
          break;
        case 13:
          output += f((current + (c >> 14))+32);
          current = (c & 16383) << 1;
          break;
        case 14:
          output += f((current + (c >> 15))+32, (c & 32767)+32);
          status = 0;
          break;
      }
    }
    
    return output + f(current + 32);
  },
  

  decompressFromUTF16 : function (input) {
    if (input == null) return "";
    var output = "",
        current,c,
        status=0,
        i = 0,
        f = LZString._f;
    
    while (i < input.length) {
      c = input.charCodeAt(i) - 32;
      
      switch (status++) {
        case 0:
          current = c << 1;
          break;
        case 1:
          output += f(current | (c >> 14));
          current = (c&16383) << 2;
          break;
        case 2:
          output += f(current | (c >> 13));
          current = (c&8191) << 3;
          break;
        case 3:
          output += f(current | (c >> 12));
          current = (c&4095) << 4;
          break;
        case 4:
          output += f(current | (c >> 11));
          current = (c&2047) << 5;
          break;
        case 5:
          output += f(current | (c >> 10));
          current = (c&1023) << 6;
          break;
        case 6:
          output += f(current | (c >> 9));
          current = (c&511) << 7;
          break;
        case 7:
          output += f(current | (c >> 8));
          current = (c&255) << 8;
          break;
        case 8:
          output += f(current | (c >> 7));
          current = (c&127) << 9;
          break;
        case 9:
          output += f(current | (c >> 6));
          current = (c&63) << 10;
          break;
        case 10:
          output += f(current | (c >> 5));
          current = (c&31) << 11;
          break;
        case 11:
          output += f(current | (c >> 4));
          current = (c&15) << 12;
          break;
        case 12:
          output += f(current | (c >> 3));
          current = (c&7) << 13;
          break;
        case 13:
          output += f(current | (c >> 2));
          current = (c&3) << 14;
          break;
        case 14:
          output += f(current | (c >> 1));
          current = (c&1) << 15;
          break;
        case 15:
          output += f(current | c);
          status=0;
          break;
      }
      
      
      i++;
    }
    
    return LZString.decompress(output);
    //return output;
    
  },


  
  compress: function (uncompressed) {
    if (uncompressed == null) return "";
    var i, value,
        context_dictionary= {},
        context_dictionaryToCreate= {},
        context_c="",
        context_wc="",
        context_w="",
        context_enlargeIn= 2, // Compensate for the first entry which should not count
        context_dictSize= 3,
        context_numBits= 2,
        context_data_string="", 
        context_data_val=0, 
        context_data_position=0,
        ii,
        f=LZString._f;
    
    for (ii = 0; ii < uncompressed.length; ii += 1) {
      context_c = uncompressed.charAt(ii);
      if (!Object.prototype.hasOwnProperty.call(context_dictionary,context_c)) {
        context_dictionary[context_c] = context_dictSize++;
        context_dictionaryToCreate[context_c] = true;
      }
      
      context_wc = context_w + context_c;
      if (Object.prototype.hasOwnProperty.call(context_dictionary,context_wc)) {
        context_w = context_wc;
      } else {
        if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
          if (context_w.charCodeAt(0)<256) {
            for (i=0 ; i<context_numBits ; i++) {
              context_data_val = (context_data_val << 1);
              if (context_data_position == 15) {
                context_data_position = 0;
                context_data_string += f(context_data_val);
                context_data_val = 0;
              } else {
                context_data_position++;
              }
            }
            value = context_w.charCodeAt(0);
            for (i=0 ; i<8 ; i++) {
              context_data_val = (context_data_val << 1) | (value&1);
              if (context_data_position == 15) {
                context_data_position = 0;
                context_data_string += f(context_data_val);
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = value >> 1;
            }
          } else {
            value = 1;
            for (i=0 ; i<context_numBits ; i++) {
              context_data_val = (context_data_val << 1) | value;
              if (context_data_position == 15) {
                context_data_position = 0;
                context_data_string += f(context_data_val);
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = 0;
            }
            value = context_w.charCodeAt(0);
            for (i=0 ; i<16 ; i++) {
              context_data_val = (context_data_val << 1) | (value&1);
              if (context_data_position == 15) {
                context_data_position = 0;
                context_data_string += f(context_data_val);
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = value >> 1;
            }
          }
          context_enlargeIn--;
          if (context_enlargeIn == 0) {
            context_enlargeIn = Math.pow(2, context_numBits);
            context_numBits++;
          }
          delete context_dictionaryToCreate[context_w];
        } else {
          value = context_dictionary[context_w];
          for (i=0 ; i<context_numBits ; i++) {
            context_data_val = (context_data_val << 1) | (value&1);
            if (context_data_position == 15) {
              context_data_position = 0;
              context_data_string += f(context_data_val);
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }
          
          
        }
        context_enlargeIn--;
        if (context_enlargeIn == 0) {
          context_enlargeIn = Math.pow(2, context_numBits);
          context_numBits++;
        }
        // Add wc to the dictionary.
        context_dictionary[context_wc] = context_dictSize++;
        context_w = String(context_c);
      }
    }
    
    // Output the code for w.
    if (context_w !== "") {
      if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
        if (context_w.charCodeAt(0)<256) {
          for (i=0 ; i<context_numBits ; i++) {
            context_data_val = (context_data_val << 1);
            if (context_data_position == 15) {
              context_data_position = 0;
              context_data_string += f(context_data_val);
              context_data_val = 0;
            } else {
              context_data_position++;
            }
          }
          value = context_w.charCodeAt(0);
          for (i=0 ; i<8 ; i++) {
            context_data_val = (context_data_val << 1) | (value&1);
            if (context_data_position == 15) {
              context_data_position = 0;
              context_data_string += f(context_data_val);
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }
        } else {
          value = 1;
          for (i=0 ; i<context_numBits ; i++) {
            context_data_val = (context_data_val << 1) | value;
            if (context_data_position == 15) {
              context_data_position = 0;
              context_data_string += f(context_data_val);
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = 0;
          }
          value = context_w.charCodeAt(0);
          for (i=0 ; i<16 ; i++) {
            context_data_val = (context_data_val << 1) | (value&1);
            if (context_data_position == 15) {
              context_data_position = 0;
              context_data_string += f(context_data_val);
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }
        }
        context_enlargeIn--;
        if (context_enlargeIn == 0) {
          context_enlargeIn = Math.pow(2, context_numBits);
          context_numBits++;
        }
        delete context_dictionaryToCreate[context_w];
      } else {
        value = context_dictionary[context_w];
        for (i=0 ; i<context_numBits ; i++) {
          context_data_val = (context_data_val << 1) | (value&1);
          if (context_data_position == 15) {
            context_data_position = 0;
            context_data_string += f(context_data_val);
            context_data_val = 0;
          } else {
            context_data_position++;
          }
          value = value >> 1;
        }
        
        
      }
      context_enlargeIn--;
      if (context_enlargeIn == 0) {
        context_enlargeIn = Math.pow(2, context_numBits);
        context_numBits++;
      }
    }
    
    // Mark the end of the stream
    value = 2;
    for (i=0 ; i<context_numBits ; i++) {
      context_data_val = (context_data_val << 1) | (value&1);
      if (context_data_position == 15) {
        context_data_position = 0;
        context_data_string += f(context_data_val);
        context_data_val = 0;
      } else {
        context_data_position++;
      }
      value = value >> 1;
    }
    
    // Flush the last char
    while (true) {
      context_data_val = (context_data_val << 1);
      if (context_data_position == 15) {
        context_data_string += f(context_data_val);
        break;
      }
      else context_data_position++;
    }
    return context_data_string;
  },
  
  decompress: function (compressed) {
    if (compressed == null) return "";
    if (compressed == "") return null;
    var dictionary = [],
        next,
        enlargeIn = 4,
        dictSize = 4,
        numBits = 3,
        entry = "",
        result = "",
        i,
        w,
        bits, resb, maxpower, power,
        c,
        f = LZString._f,
        data = {string:compressed, val:compressed.charCodeAt(0), position:32768, index:1};
    
    for (i = 0; i < 3; i += 1) {
      dictionary[i] = i;
    }
    
    bits = 0;
    maxpower = Math.pow(2,2);
    power=1;
    while (power!=maxpower) {
      resb = data.val & data.position;
      data.position >>= 1;
      if (data.position == 0) {
        data.position = 32768;
        data.val = data.string.charCodeAt(data.index++);
      }
      bits |= (resb>0 ? 1 : 0) * power;
      power <<= 1;
    }
    
    switch (next = bits) {
      case 0: 
          bits = 0;
          maxpower = Math.pow(2,8);
          power=1;
          while (power!=maxpower) {
            resb = data.val & data.position;
            data.position >>= 1;
            if (data.position == 0) {
              data.position = 32768;
              data.val = data.string.charCodeAt(data.index++);
            }
            bits |= (resb>0 ? 1 : 0) * power;
            power <<= 1;
          }
        c = f(bits);
        break;
      case 1: 
          bits = 0;
          maxpower = Math.pow(2,16);
          power=1;
          while (power!=maxpower) {
            resb = data.val & data.position;
            data.position >>= 1;
            if (data.position == 0) {
              data.position = 32768;
              data.val = data.string.charCodeAt(data.index++);
            }
            bits |= (resb>0 ? 1 : 0) * power;
            power <<= 1;
          }
        c = f(bits);
        break;
      case 2: 
        return "";
    }
    dictionary[3] = c;
    w = result = c;
    while (true) {
      if (data.index > data.string.length) {
        return "";
      }
      
      bits = 0;
      maxpower = Math.pow(2,numBits);
      power=1;
      while (power!=maxpower) {
        resb = data.val & data.position;
        data.position >>= 1;
        if (data.position == 0) {
          data.position = 32768;
          data.val = data.string.charCodeAt(data.index++);
        }
        bits |= (resb>0 ? 1 : 0) * power;
        power <<= 1;
      }

      switch (c = bits) {
        case 0: 
          bits = 0;
          maxpower = Math.pow(2,8);
          power=1;
          while (power!=maxpower) {
            resb = data.val & data.position;
            data.position >>= 1;
            if (data.position == 0) {
              data.position = 32768;
              data.val = data.string.charCodeAt(data.index++);
            }
            bits |= (resb>0 ? 1 : 0) * power;
            power <<= 1;
          }

          dictionary[dictSize++] = f(bits);
          c = dictSize-1;
          enlargeIn--;
          break;
        case 1: 
          bits = 0;
          maxpower = Math.pow(2,16);
          power=1;
          while (power!=maxpower) {
            resb = data.val & data.position;
            data.position >>= 1;
            if (data.position == 0) {
              data.position = 32768;
              data.val = data.string.charCodeAt(data.index++);
            }
            bits |= (resb>0 ? 1 : 0) * power;
            power <<= 1;
          }
          dictionary[dictSize++] = f(bits);
          c = dictSize-1;
          enlargeIn--;
          break;
        case 2: 
          return result;
      }
      
      if (enlargeIn == 0) {
        enlargeIn = Math.pow(2, numBits);
        numBits++;
      }
      
      if (dictionary[c]) {
        entry = dictionary[c];
      } else {
        if (c === dictSize) {
          entry = w + w.charAt(0);
        } else {
          return null;
        }
      }
      result += entry;
      
      // Add w+entry[0] to the dictionary.
      dictionary[dictSize++] = w + entry.charAt(0);
      enlargeIn--;
      
      w = entry;
      
      if (enlargeIn == 0) {
        enlargeIn = Math.pow(2, numBits);
        numBits++;
      }
      
    }
  }
};

if( typeof module !== 'undefined' && module != null ) {
  module.exports = LZString
}
//     uuid.js
//
//     Copyright (c) 2010-2012 Robert Kieffer
//     MIT License - http://opensource.org/licenses/mit-license.php

(function() {
  var _global = this;

  // Unique ID creation requires a high quality random # generator.  We feature
  // detect to determine the best RNG source, normalizing to a function that
  // returns 128-bits of randomness, since that's what's usually required
  var _rng;

  // Allow for MSIE11 msCrypto
  var _crypto = _global.crypto || _global.msCrypto;

  // Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
  //
  // Moderately fast, high quality
  if (typeof(_global.require) == 'function') {
    try {
      var _rb = _global.require('crypto').randomBytes;
      _rng = _rb && function() {return _rb(16);};
    } catch(e) {}
  }

  if (!_rng && _crypto && _crypto.getRandomValues) {
    // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
    //
    // Moderately fast, high quality
    var _rnds8 = new Uint8Array(16);
    _rng = function whatwgRNG() {
      _crypto.getRandomValues(_rnds8);
      return _rnds8;
    };
  }

  if (!_rng) {
    // Math.random()-based (RNG)
    //
    // If all else fails, use Math.random().  It's fast, but is of unspecified
    // quality.
    var  _rnds = new Array(16);
    _rng = function() {
      for (var i = 0, r; i < 16; i++) {
        if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
        _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
      }

      return _rnds;
    };
  }

  // Buffer class to use
  var BufferClass = typeof(_global.Buffer) == 'function' ? _global.Buffer : Array;

  // Maps for number <-> hex string conversion
  var _byteToHex = [];
  var _hexToByte = {};
  for (var i = 0; i < 256; i++) {
    _byteToHex[i] = (i + 0x100).toString(16).substr(1);
    _hexToByte[_byteToHex[i]] = i;
  }

  // **`parse()` - Parse a UUID into it's component bytes**
  function parse(s, buf, offset) {
    var i = (buf && offset) || 0, ii = 0;

    buf = buf || [];
    s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
      if (ii < 16) { // Don't overflow!
        buf[i + ii++] = _hexToByte[oct];
      }
    });

    // Zero out remaining bytes if string was short
    while (ii < 16) {
      buf[i + ii++] = 0;
    }

    return buf;
  }

  // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
  function unparse(buf, offset) {
    var i = offset || 0, bth = _byteToHex;
    return  bth[buf[i++]] + bth[buf[i++]] +
            bth[buf[i++]] + bth[buf[i++]] + '-' +
            bth[buf[i++]] + bth[buf[i++]] + '-' +
            bth[buf[i++]] + bth[buf[i++]] + '-' +
            bth[buf[i++]] + bth[buf[i++]] + '-' +
            bth[buf[i++]] + bth[buf[i++]] +
            bth[buf[i++]] + bth[buf[i++]] +
            bth[buf[i++]] + bth[buf[i++]];
  }

  // **`v1()` - Generate time-based UUID**
  //
  // Inspired by https://github.com/LiosK/UUID.js
  // and http://docs.python.org/library/uuid.html

  // random #'s we need to init node and clockseq
  var _seedBytes = _rng();

  // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
  var _nodeId = [
    _seedBytes[0] | 0x01,
    _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
  ];

  // Per 4.2.2, randomize (14 bit) clockseq
  var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;

  // Previous uuid creation time
  var _lastMSecs = 0, _lastNSecs = 0;

  // See https://github.com/broofa/node-uuid for API details
  function v1(options, buf, offset) {
    var i = buf && offset || 0;
    var b = buf || [];

    options = options || {};

    var clockseq = options.clockseq != null ? options.clockseq : _clockseq;

    // UUID timestamps are 100 nano-second units since the Gregorian epoch,
    // (1582-10-15 00:00).  JSNumbers aren't precise enough for this, so
    // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
    // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
    var msecs = options.msecs != null ? options.msecs : new Date().getTime();

    // Per 4.2.1.2, use count of uuid's generated during the current clock
    // cycle to simulate higher resolution clock
    var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1;

    // Time since last uuid creation (in msecs)
    var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;

    // Per 4.2.1.2, Bump clockseq on clock regression
    if (dt < 0 && options.clockseq == null) {
      clockseq = clockseq + 1 & 0x3fff;
    }

    // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
    // time interval
    if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
      nsecs = 0;
    }

    // Per 4.2.1.2 Throw error if too many uuids are requested
    if (nsecs >= 10000) {
      throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
    }

    _lastMSecs = msecs;
    _lastNSecs = nsecs;
    _clockseq = clockseq;

    // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
    msecs += 12219292800000;

    // `time_low`
    var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
    b[i++] = tl >>> 24 & 0xff;
    b[i++] = tl >>> 16 & 0xff;
    b[i++] = tl >>> 8 & 0xff;
    b[i++] = tl & 0xff;

    // `time_mid`
    var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
    b[i++] = tmh >>> 8 & 0xff;
    b[i++] = tmh & 0xff;

    // `time_high_and_version`
    b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
    b[i++] = tmh >>> 16 & 0xff;

    // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
    b[i++] = clockseq >>> 8 | 0x80;

    // `clock_seq_low`
    b[i++] = clockseq & 0xff;

    // `node`
    var node = options.node || _nodeId;
    for (var n = 0; n < 6; n++) {
      b[i + n] = node[n];
    }

    return buf ? buf : unparse(b);
  }

  // **`v4()` - Generate random UUID**

  // See https://github.com/broofa/node-uuid for API details
  function v4(options, buf, offset) {
    // Deprecated - 'format' argument, as supported in v1.2
    var i = buf && offset || 0;

    if (typeof(options) == 'string') {
      buf = options == 'binary' ? new BufferClass(16) : null;
      options = null;
    }
    options = options || {};

    var rnds = options.random || (options.rng || _rng)();

    // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
    rnds[6] = (rnds[6] & 0x0f) | 0x40;
    rnds[8] = (rnds[8] & 0x3f) | 0x80;

    // Copy bytes to buffer, if provided
    if (buf) {
      for (var ii = 0; ii < 16; ii++) {
        buf[i + ii] = rnds[ii];
      }
    }

    return buf || unparse(rnds);
  }

  // Export public API
  var uuid = v4;
  uuid.v1 = v1;
  uuid.v4 = v4;
  uuid.parse = parse;
  uuid.unparse = unparse;
  uuid.BufferClass = BufferClass;

  if (typeof(module) != 'undefined' && module.exports) {
    // Publish as node.js module
    module.exports = uuid;
  } else  if (typeof define === 'function' && define.amd) {
    // Publish as AMD module
    define(function() {return uuid;});
 

  } else {
    // Publish as global (in browsers)
    var _previousRoot = _global.uuid;

    // **`noConflict()` - (browser only) to reset global 'uuid' var**
    uuid.noConflict = function() {
      _global.uuid = _previousRoot;
      return uuid;
    };

    _global.uuid = uuid;
  }
}).call(this);
/*! modernizr 3.2.0 (Custom Build) | MIT *
 * http://modernizr.com/download/?-cssfilters-webgl-prefixed-prefixedcss-prefixedcssvalue-testallprops-testprop-teststyles !*/
!function(e,n,t){function r(e,n){return typeof e===n}function o(){var e,n,t,o,s,i,a;for(var f in C)if(C.hasOwnProperty(f)){if(e=[],n=C[f],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t<n.options.aliases.length;t++)e.push(n.options.aliases[t].toLowerCase());for(o=r(n.fn,"function")?n.fn():n.fn,s=0;s<e.length;s++)i=e[s],a=i.split("."),1===a.length?Modernizr[a[0]]=o:(!Modernizr[a[0]]||Modernizr[a[0]]instanceof Boolean||(Modernizr[a[0]]=new Boolean(Modernizr[a[0]])),Modernizr[a[0]][a[1]]=o),h.push((o?"":"no-")+a.join("-"))}}function s(e){var n=x.className,t=Modernizr._config.classPrefix||"";if(w&&(n=n.baseVal),Modernizr._config.enableJSClass){var r=new RegExp("(^|\\s)"+t+"no-js(\\s|$)");n=n.replace(r,"$1"+t+"js$2")}Modernizr._config.enableClasses&&(n+=" "+t+e.join(" "+t),w?x.className.baseVal=n:x.className=n)}function i(e){return e.replace(/([a-z])-([a-z])/g,function(e,n,t){return n+t.toUpperCase()}).replace(/^-/,"")}function a(){return"function"!=typeof n.createElement?n.createElement(arguments[0]):w?n.createElementNS.call(n,"http://www.w3.org/2000/svg",arguments[0]):n.createElement.apply(n,arguments)}function f(e){return e.replace(/([A-Z])/g,function(e,n){return"-"+n.toLowerCase()}).replace(/^ms-/,"-ms-")}function l(e,n){return!!~(""+e).indexOf(n)}function u(){var e=n.body;return e||(e=a(w?"svg":"body"),e.fake=!0),e}function p(e,t,r,o){var s,i,f,l,p="modernizr",d=a("div"),c=u();if(parseInt(r,10))for(;r--;)f=a("div"),f.id=o?o[r]:p+(r+1),d.appendChild(f);return s=a("style"),s.type="text/css",s.id="s"+p,(c.fake?c:d).appendChild(s),c.appendChild(d),s.styleSheet?s.styleSheet.cssText=e:s.appendChild(n.createTextNode(e)),d.id=p,c.fake&&(c.style.background="",c.style.overflow="hidden",l=x.style.overflow,x.style.overflow="hidden",x.appendChild(c)),i=t(d,e),c.fake?(c.parentNode.removeChild(c),x.style.overflow=l,x.offsetHeight):d.parentNode.removeChild(d),!!i}function d(n,r){var o=n.length;if("CSS"in e&&"supports"in e.CSS){for(;o--;)if(e.CSS.supports(f(n[o]),r))return!0;return!1}if("CSSSupportsRule"in e){for(var s=[];o--;)s.push("("+f(n[o])+":"+r+")");return s=s.join(" or "),p("@supports ("+s+") { #modernizr { position: absolute; } }",function(e){return"absolute"==getComputedStyle(e,null).position})}return t}function c(e,n){return function(){return e.apply(n,arguments)}}function v(e,n,t){var o;for(var s in e)if(e[s]in n)return t===!1?e[s]:(o=n[e[s]],r(o,"function")?c(o,t||n):o);return!1}function m(e,n,o,s){function f(){p&&(delete k.style,delete k.modElem)}if(s=r(s,"undefined")?!1:s,!r(o,"undefined")){var u=d(e,o);if(!r(u,"undefined"))return u}for(var p,c,v,m,y,g=["modernizr","tspan"];!k.style;)p=!0,k.modElem=a(g.shift()),k.style=k.modElem.style;for(v=e.length,c=0;v>c;c++)if(m=e[c],y=k.style[m],l(m,"-")&&(m=i(m)),k.style[m]!==t){if(s||r(o,"undefined"))return f(),"pfx"==n?m:!0;try{k.style[m]=o}catch(h){}if(k.style[m]!=y)return f(),"pfx"==n?m:!0}return f(),!1}function y(e,n,t,o,s){var i=e.charAt(0).toUpperCase()+e.slice(1),a=(e+" "+T.join(i+" ")+i).split(" ");return r(n,"string")||r(n,"undefined")?m(a,n,o,s):(a=(e+" "+N.join(i+" ")+i).split(" "),v(a,n,t))}function g(e,n,r){return y(e,t,t,n,r)}var h=[],C=[],S={_version:"3.2.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,n){var t=this;setTimeout(function(){n(t[e])},0)},addTest:function(e,n,t){C.push({name:e,fn:n,options:t})},addAsyncTest:function(e){C.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=S,Modernizr=new Modernizr;var x=n.documentElement,w="svg"===x.nodeName.toLowerCase();Modernizr.addTest("webgl",function(){var n=a("canvas"),t="probablySupportsContext"in n?"probablySupportsContext":"supportsContext";return t in n?n[t]("webgl")||n[t]("experimental-webgl"):"WebGLRenderingContext"in e});var b=S._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):[];S._prefixes=b;var _="CSS"in e&&"supports"in e.CSS,P="supportsCSS"in e;Modernizr.addTest("supports",_||P);var E=(S.testStyles=p,"Moz O ms Webkit"),T=S._config.usePrefixes?E.split(" "):[];S._cssomPrefixes=T;var z=function(n){var r,o=b.length,s=e.CSSRule;if("undefined"==typeof s)return t;if(!n)return!1;if(n=n.replace(/^@/,""),r=n.replace(/-/g,"_").toUpperCase()+"_RULE",r in s)return"@"+n;for(var i=0;o>i;i++){var a=b[i],f=a.toUpperCase()+"_"+r;if(f in s)return"@-"+a.toLowerCase()+"-"+n}return!1};S.atRule=z;var N=S._config.usePrefixes?E.toLowerCase().split(" "):[];S._domPrefixes=N;var j=function(e,n){var t=!1,r=a("div"),o=r.style;if(e in o){var s=N.length;for(o[e]=n,t=o[e];s--&&!t;)o[e]="-"+N[s]+"-"+n,t=o[e]}return""===t&&(t=!1),t};S.prefixedCSSValue=j;var L={elem:a("modernizr")};Modernizr._q.push(function(){delete L.elem});var k={style:L.elem.style};Modernizr._q.unshift(function(){delete k.style});S.testProp=function(e,n,r){return m([e],t,n,r)};S.testAllProps=y;var R=S.prefixed=function(e,n,t){return 0===e.indexOf("@")?z(e):(-1!=e.indexOf("-")&&(e=i(e)),n?y(e,n,t):y(e,"pfx"))};S.prefixedCSS=function(e){var n=R(e);return n&&f(n)};S.testAllProps=g,Modernizr.addTest("cssfilters",function(){if(Modernizr.supports)return g("filter","blur(2px)");var e=a("a");return e.style.cssText=b.join("filter:blur(2px); "),!!e.style.length&&(n.documentMode===t||n.documentMode>9)}),o(),s(h),delete S.addTest,delete S.addAsyncTest;for(var A=0;A<Modernizr._q.length;A++)Modernizr._q[A]();e.Modernizr=Modernizr}(window,document);/*

  OpenLayers.js -- OpenLayers Map Viewer Library

  Copyright (c) 2006-2013 by OpenLayers Contributors
  Published under the 2-clause BSD license.
  See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors.

  Includes compressed code under the following licenses:

  (For uncompressed versions of the code used, please see the
  OpenLayers Github repository: <https://github.com/openlayers/openlayers>)

*/

/**
 * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
 * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

/**
 * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
 * Copyright (c) 2006, Yahoo! Inc.
 * All rights reserved.
 * 
 * Redistribution and use of this software in source and binary forms, with or
 * without modification, are permitted provided that the following conditions
 * are met:
 * 
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * 
 * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without
 *   specific prior written permission of Yahoo! Inc.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 */
var OpenLayers={VERSION_NUMBER:"Release 2.13",singleFile:!0,_getScriptLocation:function(){for(var a=/(^|(.*?\/))(OpenLayers[^\/]*?\.js)(\?|$)/,b=document.getElementsByTagName("script"),c,d="",e=0,f=b.length;e<f;e++)if(c=b[e].getAttribute("src"))if(c=c.match(a)){d=c[1];break}return function(){return d}}(),ImgPath:""};OpenLayers.Class=function(){var a=arguments.length,b=arguments[0],c=arguments[a-1],d="function"==typeof c.initialize?c.initialize:function(){b.prototype.initialize.apply(this,arguments)};1<a?(a=[d,b].concat(Array.prototype.slice.call(arguments).slice(1,a-1),c),OpenLayers.inherit.apply(null,a)):d.prototype=c;return d};
OpenLayers.inherit=function(a,b){var c=function(){};c.prototype=b.prototype;a.prototype=new c;var d,e,c=2;for(d=arguments.length;c<d;c++)e=arguments[c],"function"===typeof e&&(e=e.prototype),OpenLayers.Util.extend(a.prototype,e)};OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.extend=function(a,b){a=a||{};if(b){for(var c in b){var d=b[c];void 0!==d&&(a[c]=d)}"function"==typeof window.Event&&b instanceof window.Event||(!b.hasOwnProperty||!b.hasOwnProperty("toString"))||(a.toString=b.toString)}return a};OpenLayers.String={startsWith:function(a,b){return 0==a.indexOf(b)},contains:function(a,b){return-1!=a.indexOf(b)},trim:function(a){return a.replace(/^\s\s*/,"").replace(/\s\s*$/,"")},camelize:function(a){a=a.split("-");for(var b=a[0],c=1,d=a.length;c<d;c++)var e=a[c],b=b+(e.charAt(0).toUpperCase()+e.substring(1));return b},format:function(a,b,c){b||(b=window);return a.replace(OpenLayers.String.tokenRegEx,function(a,e){for(var f,g=e.split(/\.+/),h=0;h<g.length;h++){0==h&&(f=b);if(void 0===f)break;
f=f[g[h]]}"function"==typeof f&&(f=c?f.apply(null,c):f());return"undefined"==typeof f?"undefined":f})},tokenRegEx:/\$\{([\w.]+?)\}/g,numberRegEx:/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,isNumeric:function(a){return OpenLayers.String.numberRegEx.test(a)},numericIf:function(a,b){var c=a;!0===b&&(null!=a&&a.replace)&&(a=a.replace(/^\s*|\s*$/g,""));return OpenLayers.String.isNumeric(a)?parseFloat(a):c}};
OpenLayers.Number={decimalSeparator:".",thousandsSeparator:",",limitSigDigs:function(a,b){var c=0;0<b&&(c=parseFloat(a.toPrecision(b)));return c},format:function(a,b,c,d){b="undefined"!=typeof b?b:0;c="undefined"!=typeof c?c:OpenLayers.Number.thousandsSeparator;d="undefined"!=typeof d?d:OpenLayers.Number.decimalSeparator;null!=b&&(a=parseFloat(a.toFixed(b)));var e=a.toString().split(".");1==e.length&&null==b&&(b=0);a=e[0];if(c)for(var f=/(-?[0-9]+)([0-9]{3})/;f.test(a);)a=a.replace(f,"$1"+c+"$2");
0==b?b=a:(c=1<e.length?e[1]:"0",null!=b&&(c+=Array(b-c.length+1).join("0")),b=a+d+c);return b},zeroPad:function(a,b,c){for(a=a.toString(c||10);a.length<b;)a="0"+a;return a}};
OpenLayers.Function={bind:function(a,b){var c=Array.prototype.slice.apply(arguments,[2]);return function(){var d=c.concat(Array.prototype.slice.apply(arguments,[0]));return a.apply(b,d)}},bindAsEventListener:function(a,b){return function(c){return a.call(b,c||window.event)}},False:function(){return!1},True:function(){return!0},Void:function(){}};
OpenLayers.Array={filter:function(a,b,c){var d=[];if(Array.prototype.filter)d=a.filter(b,c);else{var e=a.length;if("function"!=typeof b)throw new TypeError;for(var f=0;f<e;f++)if(f in a){var g=a[f];b.call(c,g,f,a)&&d.push(g)}}return d}};OpenLayers.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,centerLonLat:null,initialize:function(a,b,c,d){OpenLayers.Util.isArray(a)&&(d=a[3],c=a[2],b=a[1],a=a[0]);null!=a&&(this.left=OpenLayers.Util.toFloat(a));null!=b&&(this.bottom=OpenLayers.Util.toFloat(b));null!=c&&(this.right=OpenLayers.Util.toFloat(c));null!=d&&(this.top=OpenLayers.Util.toFloat(d))},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top)},equals:function(a){var b=!1;null!=
a&&(b=this.left==a.left&&this.right==a.right&&this.top==a.top&&this.bottom==a.bottom);return b},toString:function(){return[this.left,this.bottom,this.right,this.top].join()},toArray:function(a){return!0===a?[this.bottom,this.left,this.top,this.right]:[this.left,this.bottom,this.right,this.top]},toBBOX:function(a,b){null==a&&(a=6);var c=Math.pow(10,a),d=Math.round(this.left*c)/c,e=Math.round(this.bottom*c)/c,f=Math.round(this.right*c)/c,c=Math.round(this.top*c)/c;return!0===b?e+","+d+","+c+","+f:d+
","+e+","+f+","+c},toGeometry:function(){return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(this.left,this.bottom),new OpenLayers.Geometry.Point(this.right,this.bottom),new OpenLayers.Geometry.Point(this.right,this.top),new OpenLayers.Geometry.Point(this.left,this.top)])])},getWidth:function(){return this.right-this.left},getHeight:function(){return this.top-this.bottom},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight())},
getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2)},getCenterLonLat:function(){this.centerLonLat||(this.centerLonLat=new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2));return this.centerLonLat},scale:function(a,b){null==b&&(b=this.getCenterLonLat());var c,d;"OpenLayers.LonLat"==b.CLASS_NAME?(c=b.lon,d=b.lat):(c=b.x,d=b.y);return new OpenLayers.Bounds((this.left-c)*a+c,(this.bottom-d)*a+d,(this.right-c)*a+c,(this.top-d)*a+
d)},add:function(a,b){if(null==a||null==b)throw new TypeError("Bounds.add cannot receive null values");return new OpenLayers.Bounds(this.left+a,this.bottom+b,this.right+a,this.top+b)},extend:function(a){if(a)switch(a.CLASS_NAME){case "OpenLayers.LonLat":this.extendXY(a.lon,a.lat);break;case "OpenLayers.Geometry.Point":this.extendXY(a.x,a.y);break;case "OpenLayers.Bounds":this.centerLonLat=null;if(null==this.left||a.left<this.left)this.left=a.left;if(null==this.bottom||a.bottom<this.bottom)this.bottom=
a.bottom;if(null==this.right||a.right>this.right)this.right=a.right;if(null==this.top||a.top>this.top)this.top=a.top}},extendXY:function(a,b){this.centerLonLat=null;if(null==this.left||a<this.left)this.left=a;if(null==this.bottom||b<this.bottom)this.bottom=b;if(null==this.right||a>this.right)this.right=a;if(null==this.top||b>this.top)this.top=b},containsLonLat:function(a,b){"boolean"===typeof b&&(b={inclusive:b});b=b||{};var c=this.contains(a.lon,a.lat,b.inclusive),d=b.worldBounds;d&&!c&&(c=d.getWidth(),
d=Math.round((a.lon-(d.left+d.right)/2)/c),c=this.containsLonLat({lon:a.lon-d*c,lat:a.lat},{inclusive:b.inclusive}));return c},containsPixel:function(a,b){return this.contains(a.x,a.y,b)},contains:function(a,b,c){null==c&&(c=!0);if(null==a||null==b)return!1;a=OpenLayers.Util.toFloat(a);b=OpenLayers.Util.toFloat(b);var d=!1;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&a<this.right&&b>this.bottom&&b<this.top},intersectsBounds:function(a,b){"boolean"===typeof b&&(b=
{inclusive:b});b=b||{};if(b.worldBounds){var c=this.wrapDateLine(b.worldBounds);a=a.wrapDateLine(b.worldBounds)}else c=this;null==b.inclusive&&(b.inclusive=!0);var d=!1,e=c.left==a.right||c.right==a.left||c.top==a.bottom||c.bottom==a.top;if(b.inclusive||!e)var d=a.top>=c.bottom&&a.top<=c.top||c.top>a.bottom&&c.top<a.top,e=a.left>=c.left&&a.left<=c.right||c.left>=a.left&&c.left<=a.right,f=a.right>=c.left&&a.right<=c.right||c.right>=a.left&&c.right<=a.right,d=(a.bottom>=c.bottom&&a.bottom<=c.top||c.bottom>=
a.bottom&&c.bottom<=a.top||d)&&(e||f);if(b.worldBounds&&!d){var g=b.worldBounds,e=g.getWidth(),f=!g.containsBounds(c),g=!g.containsBounds(a);f&&!g?(a=a.add(-e,0),d=c.intersectsBounds(a,{inclusive:b.inclusive})):g&&!f&&(c=c.add(-e,0),d=a.intersectsBounds(c,{inclusive:b.inclusive}))}return d},containsBounds:function(a,b,c){null==b&&(b=!1);null==c&&(c=!0);var d=this.contains(a.left,a.bottom,c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c);a=this.contains(a.right,a.top,c);return b?
d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat(),b=b+(a.lat<c.lat?"b":"t");return b+=a.lon<c.lon?"l":"r"},transform:function(a,b){this.centerLonLat=null;var c=OpenLayers.Projection.transform({x:this.left,y:this.bottom},a,b),d=OpenLayers.Projection.transform({x:this.right,y:this.bottom},a,b),e=OpenLayers.Projection.transform({x:this.left,y:this.top},a,b),f=OpenLayers.Projection.transform({x:this.right,y:this.top},a,b);this.left=Math.min(c.x,e.x);this.bottom=Math.min(c.y,
d.y);this.right=Math.max(d.x,f.x);this.top=Math.max(e.y,f.y);return this},wrapDateLine:function(a,b){b=b||{};var c=b.leftTolerance||0,d=b.rightTolerance||0,e=this.clone();if(a){for(var f=a.getWidth();e.left<a.left&&e.right-d<=a.left;)e=e.add(f,0);for(;e.left+c>=a.right&&e.right>a.right;)e=e.add(-f,0);c=e.left+c;c<a.right&&(c>a.left&&e.right-d>a.right)&&(e=e.add(-f,0))}return e},CLASS_NAME:"OpenLayers.Bounds"});
OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)};OpenLayers.Bounds.fromArray=function(a,b){return!0===b?new OpenLayers.Bounds(a[1],a[0],a[3],a[2]):new OpenLayers.Bounds(a[0],a[1],a[2],a[3])};OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)};OpenLayers.Bounds.oppositeQuadrant=function(a){var b;b=""+("t"==a.charAt(0)?"b":"t");return b+="l"==a.charAt(1)?"r":"l"};OpenLayers.Element={visible:function(a){return"none"!=OpenLayers.Util.getElement(a).style.display},toggle:function(){for(var a=0,b=arguments.length;a<b;a++){var c=OpenLayers.Util.getElement(arguments[a]),d=OpenLayers.Element.visible(c)?"none":"";c.style.display=d}},remove:function(a){a=OpenLayers.Util.getElement(a);a.parentNode.removeChild(a)},getHeight:function(a){a=OpenLayers.Util.getElement(a);return a.offsetHeight},hasClass:function(a,b){var c=a.className;return!!c&&RegExp("(^|\\s)"+b+"(\\s|$)").test(c)},
addClass:function(a,b){OpenLayers.Element.hasClass(a,b)||(a.className+=(a.className?" ":"")+b);return a},removeClass:function(a,b){var c=a.className;c&&(a.className=OpenLayers.String.trim(c.replace(RegExp("(^|\\s+)"+b+"(\\s+|$)")," ")));return a},toggleClass:function(a,b){OpenLayers.Element.hasClass(a,b)?OpenLayers.Element.removeClass(a,b):OpenLayers.Element.addClass(a,b);return a},getStyle:function(a,b){a=OpenLayers.Util.getElement(a);var c=null;if(a&&a.style){c=a.style[OpenLayers.String.camelize(b)];
c||(document.defaultView&&document.defaultView.getComputedStyle?c=(c=document.defaultView.getComputedStyle(a,null))?c.getPropertyValue(b):null:a.currentStyle&&(c=a.currentStyle[OpenLayers.String.camelize(b)]));var d=["left","top","right","bottom"];window.opera&&(-1!=OpenLayers.Util.indexOf(d,b)&&"static"==OpenLayers.Element.getStyle(a,"position"))&&(c="auto")}return"auto"==c?null:c}};OpenLayers.LonLat=OpenLayers.Class({lon:0,lat:0,initialize:function(a,b){OpenLayers.Util.isArray(a)&&(b=a[1],a=a[0]);this.lon=OpenLayers.Util.toFloat(a);this.lat=OpenLayers.Util.toFloat(b)},toString:function(){return"lon="+this.lon+",lat="+this.lat},toShortString:function(){return this.lon+", "+this.lat},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat)},add:function(a,b){if(null==a||null==b)throw new TypeError("LonLat.add cannot receive null values");return new OpenLayers.LonLat(this.lon+
OpenLayers.Util.toFloat(a),this.lat+OpenLayers.Util.toFloat(b))},equals:function(a){var b=!1;null!=a&&(b=this.lon==a.lon&&this.lat==a.lat||isNaN(this.lon)&&isNaN(this.lat)&&isNaN(a.lon)&&isNaN(a.lat));return b},transform:function(a,b){var c=OpenLayers.Projection.transform({x:this.lon,y:this.lat},a,b);this.lon=c.x;this.lat=c.y;return this},wrapDateLine:function(a){var b=this.clone();if(a){for(;b.lon<a.left;)b.lon+=a.getWidth();for(;b.lon>a.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"});
OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])};OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=!1;null!=a&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(null==a||null==b)throw new TypeError("Pixel.add cannot receive null values");
return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();a&&(b=this.add(a.x,a.y));return b},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=!1;null!=a&&(b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h));return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(a){alert(a)},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};
(function(){for(var a=document.getElementsByTagName("script"),b=0,c=a.length;b<c;++b)if(-1!=a[b].src.indexOf("firebug.js")&&console){OpenLayers.Util.extend(OpenLayers.Console,console);break}})();OpenLayers.Lang={code:null,defaultCode:"en",getCode:function(){OpenLayers.Lang.code||OpenLayers.Lang.setCode();return OpenLayers.Lang.code},setCode:function(a){var b;a||(a="msie"==OpenLayers.BROWSER_NAME?navigator.userLanguage:navigator.language);a=a.split("-");a[0]=a[0].toLowerCase();"object"==typeof OpenLayers.Lang[a[0]]&&(b=a[0]);if(a[1]){var c=a[0]+"-"+a[1].toUpperCase();"object"==typeof OpenLayers.Lang[c]&&(b=c)}b||(OpenLayers.Console.warn("Failed to find OpenLayers.Lang."+a.join("-")+" dictionary, falling back to default language"),
b=OpenLayers.Lang.defaultCode);OpenLayers.Lang.code=b},translate:function(a,b){var c=OpenLayers.Lang[OpenLayers.Lang.getCode()];(c=c&&c[a])||(c=a);b&&(c=OpenLayers.String.format(c,b));return c}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.getElement=function(){for(var a=[],b=0,c=arguments.length;b<c;b++){var d=arguments[b];"string"==typeof d&&(d=document.getElementById(d));if(1==arguments.length)return d;a.push(d)}return a};OpenLayers.Util.isElement=function(a){return!(!a||1!==a.nodeType)};OpenLayers.Util.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)};OpenLayers.Util.removeItem=function(a,b){for(var c=a.length-1;0<=c;c--)a[c]==b&&a.splice(c,1);return a};
OpenLayers.Util.indexOf=function(a,b){if("function"==typeof a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;c<d;c++)if(a[c]==b)return c;return-1};OpenLayers.Util.dotless=/\./g;
OpenLayers.Util.modifyDOMElement=function(a,b,c,d,e,f,g,h){b&&(a.id=b.replace(OpenLayers.Util.dotless,"_"));c&&(a.style.left=c.x+"px",a.style.top=c.y+"px");d&&(a.style.width=d.w+"px",a.style.height=d.h+"px");e&&(a.style.position=e);f&&(a.style.border=f);g&&(a.style.overflow=g);0<=parseFloat(h)&&1>parseFloat(h)?(a.style.filter="alpha(opacity="+100*h+")",a.style.opacity=h):1==parseFloat(h)&&(a.style.filter="",a.style.opacity="")};
OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var k=document.createElement("div");d&&(k.style.backgroundImage="url("+d+")");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(k,a,b,c,e,f,g,h);return k};
OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var k=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(k,a,b,c,e,f,null,g);h&&(k.style.display="none",b=function(){k.style.display="";OpenLayers.Event.stopObservingElement(k)},OpenLayers.Event.observe(k,"load",b),OpenLayers.Event.observe(k,"error",b));k.style.alt=a;k.galleryImg="no";d&&(k.src=d);return k};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;
OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(null==OpenLayers.Util.alphaHackNeeded){var a=navigator.appVersion.split("MSIE"),a=parseFloat(a[1]),b=!1;try{b=!!document.body.filters}catch(c){}OpenLayers.Util.alphaHackNeeded=b&&5.5<=a&&7>a}return OpenLayers.Util.alphaHackNeeded};
OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,k){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,k);b=a.childNodes[0];e&&(b.src=e);OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);OpenLayers.Util.alphaHack()&&("none"!=a.style.display&&(a.style.display="inline-block"),null==h&&(h="scale"),a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')",0<=parseFloat(a.style.opacity)&&1>parseFloat(a.style.opacity)&&
(a.style.filter+=" alpha(opacity="+100*a.style.opacity+")"),b.style.filter="alpha(opacity=0)")};OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,k){var l=OpenLayers.Util.createDiv();k=OpenLayers.Util.createImage(null,null,null,null,null,null,null,k);k.className="olAlphaImg";l.appendChild(k);OpenLayers.Util.modifyAlphaImageDiv(l,a,b,c,d,e,f,g,h);return l};OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b};
OpenLayers.Util.applyDefaults=function(a,b){a=a||{};var c="function"==typeof window.Event&&b instanceof window.Event,d;for(d in b)if(void 0===a[d]||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];!c&&(b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))&&(a.toString=b.toString);return a};
OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(null!=d&&"function"!=typeof d){if("object"==typeof d&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;g<h;g++)f=d[g],e.push(encodeURIComponent(null===f||void 0===f?"":f));d=e.join(",")}else d=encodeURIComponent(d);b.push(encodeURIComponent(c)+"="+d)}}return b.join("&")};OpenLayers.Util.urlAppend=function(a,b){var c=a;if(b)var d=(a+" ").split(/[?&]/),c=c+(" "===d.pop()?b:d.length?"&"+b:"?"+b);return c};
OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||OpenLayers._getScriptLocation()+"img/"};OpenLayers.Util.getImageLocation=function(a){return OpenLayers.Util.getImagesLocation()+a};OpenLayers.Util.Try=function(){for(var a=null,b=0,c=arguments.length;b<c;b++){var d=arguments[b];try{a=d();break}catch(e){}}return a};
OpenLayers.Util.getXmlNodeValue=function(a){var b=null;OpenLayers.Util.Try(function(){b=a.text;b||(b=a.textContent);b||(b=a.firstChild.nodeValue)},function(){b=a.textContent});return b};OpenLayers.Util.mouseLeft=function(a,b){for(var c=a.relatedTarget?a.relatedTarget:a.toElement;c!=b&&null!=c;)c=c.parentNode;return c!=b};OpenLayers.Util.DEFAULT_PRECISION=14;OpenLayers.Util.toFloat=function(a,b){null==b&&(b=OpenLayers.Util.DEFAULT_PRECISION);"number"!==typeof a&&(a=parseFloat(a));return 0===b?a:parseFloat(a.toPrecision(b))};
OpenLayers.Util.rad=function(a){return a*Math.PI/180};OpenLayers.Util.deg=function(a){return 180*a/Math.PI};OpenLayers.Util.VincentyConstants={a:6378137,b:6356752.3142,f:1/298.257223563};
OpenLayers.Util.distVincenty=function(a,b){for(var c=OpenLayers.Util.VincentyConstants,d=c.a,e=c.b,c=c.f,f=OpenLayers.Util.rad(b.lon-a.lon),g=Math.atan((1-c)*Math.tan(OpenLayers.Util.rad(a.lat))),h=Math.atan((1-c)*Math.tan(OpenLayers.Util.rad(b.lat))),k=Math.sin(g),g=Math.cos(g),l=Math.sin(h),h=Math.cos(h),m=f,n=2*Math.PI,p=20;1E-12<Math.abs(m-n)&&0<--p;){var q=Math.sin(m),r=Math.cos(m),s=Math.sqrt(h*q*h*q+(g*l-k*h*r)*(g*l-k*h*r));if(0==s)return 0;var r=k*l+g*h*r,t=Math.atan2(s,r),u=Math.asin(g*h*
q/s),v=Math.cos(u)*Math.cos(u),q=r-2*k*l/v,w=c/16*v*(4+c*(4-3*v)),n=m,m=f+(1-w)*c*Math.sin(u)*(t+w*s*(q+w*r*(-1+2*q*q)))}if(0==p)return NaN;d=v*(d*d-e*e)/(e*e);c=d/1024*(256+d*(-128+d*(74-47*d)));return(e*(1+d/16384*(4096+d*(-768+d*(320-175*d))))*(t-c*s*(q+c/4*(r*(-1+2*q*q)-c/6*q*(-3+4*s*s)*(-3+4*q*q))))).toFixed(3)/1E3};
OpenLayers.Util.destinationVincenty=function(a,b,c){var d=OpenLayers.Util,e=d.VincentyConstants,f=e.a,g=e.b,h=e.f,e=a.lon;a=a.lat;var k=d.rad(b);b=Math.sin(k);k=Math.cos(k);a=(1-h)*Math.tan(d.rad(a));var l=1/Math.sqrt(1+a*a),m=a*l,n=Math.atan2(a,k);a=l*b;for(var p=1-a*a,f=p*(f*f-g*g)/(g*g),q=1+f/16384*(4096+f*(-768+f*(320-175*f))),r=f/1024*(256+f*(-128+f*(74-47*f))),f=c/(g*q),s=2*Math.PI;1E-12<Math.abs(f-s);)var t=Math.cos(2*n+f),u=Math.sin(f),v=Math.cos(f),w=r*u*(t+r/4*(v*(-1+2*t*t)-r/6*t*(-3+4*
u*u)*(-3+4*t*t))),s=f,f=c/(g*q)+w;c=m*u-l*v*k;g=Math.atan2(m*v+l*u*k,(1-h)*Math.sqrt(a*a+c*c));b=Math.atan2(u*b,l*v-m*u*k);k=h/16*p*(4+h*(4-3*p));t=b-(1-k)*h*a*(f+k*u*(t+k*v*(-1+2*t*t)));Math.atan2(a,-c);return new OpenLayers.LonLat(e+d.deg(t),d.deg(g))};
OpenLayers.Util.getParameters=function(a,b){b=b||{};a=null===a||void 0===a?window.location.href:a;var c="";if(OpenLayers.String.contains(a,"?"))var d=a.indexOf("?")+1,c=OpenLayers.String.contains(a,"#")?a.indexOf("#"):a.length,c=a.substring(d,c);for(var d={},c=c.split(/[&;]/),e=0,f=c.length;e<f;++e){var g=c[e].split("=");if(g[0]){var h=g[0];try{h=decodeURIComponent(h)}catch(k){h=unescape(h)}g=(g[1]||"").replace(/\+/g," ");try{g=decodeURIComponent(g)}catch(l){g=unescape(g)}!1!==b.splitArgs&&(g=g.split(","));
1==g.length&&(g=g[0]);d[h]=g}}return d};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(a){a=null==a?"id_":a.replace(OpenLayers.Util.dotless,"_");OpenLayers.Util.lastSeqID+=1;return a+OpenLayers.Util.lastSeqID};OpenLayers.INCHES_PER_UNIT={inches:1,ft:12,mi:63360,m:39.37,km:39370,dd:4374754,yd:36};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT.degrees=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.INCHES_PER_UNIT.nmi=1852*OpenLayers.INCHES_PER_UNIT.m;
OpenLayers.METERS_PER_INCH=0.0254000508001016;
OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{Inch:OpenLayers.INCHES_PER_UNIT.inches,Meter:1/OpenLayers.METERS_PER_INCH,Foot:0.3048006096012192/OpenLayers.METERS_PER_INCH,IFoot:0.3048/OpenLayers.METERS_PER_INCH,ClarkeFoot:0.3047972651151/OpenLayers.METERS_PER_INCH,SearsFoot:0.30479947153867626/OpenLayers.METERS_PER_INCH,GoldCoastFoot:0.3047997101815088/OpenLayers.METERS_PER_INCH,IInch:0.0254/OpenLayers.METERS_PER_INCH,MicroInch:2.54E-5/OpenLayers.METERS_PER_INCH,Mil:2.54E-8/OpenLayers.METERS_PER_INCH,
Centimeter:0.01/OpenLayers.METERS_PER_INCH,Kilometer:1E3/OpenLayers.METERS_PER_INCH,Yard:0.9144018288036576/OpenLayers.METERS_PER_INCH,SearsYard:0.914398414616029/OpenLayers.METERS_PER_INCH,IndianYard:0.9143985307444408/OpenLayers.METERS_PER_INCH,IndianYd37:0.91439523/OpenLayers.METERS_PER_INCH,IndianYd62:0.9143988/OpenLayers.METERS_PER_INCH,IndianYd75:0.9143985/OpenLayers.METERS_PER_INCH,IndianFoot:0.30479951/OpenLayers.METERS_PER_INCH,IndianFt37:0.30479841/OpenLayers.METERS_PER_INCH,IndianFt62:0.3047996/
OpenLayers.METERS_PER_INCH,IndianFt75:0.3047995/OpenLayers.METERS_PER_INCH,Mile:1609.3472186944373/OpenLayers.METERS_PER_INCH,IYard:0.9144/OpenLayers.METERS_PER_INCH,IMile:1609.344/OpenLayers.METERS_PER_INCH,NautM:1852/OpenLayers.METERS_PER_INCH,"Lat-66":110943.31648893273/OpenLayers.METERS_PER_INCH,"Lat-83":110946.25736872235/OpenLayers.METERS_PER_INCH,Decimeter:0.1/OpenLayers.METERS_PER_INCH,Millimeter:0.001/OpenLayers.METERS_PER_INCH,Dekameter:10/OpenLayers.METERS_PER_INCH,Decameter:10/OpenLayers.METERS_PER_INCH,
Hectometer:100/OpenLayers.METERS_PER_INCH,GermanMeter:1.0000135965/OpenLayers.METERS_PER_INCH,CaGrid:0.999738/OpenLayers.METERS_PER_INCH,ClarkeChain:20.1166194976/OpenLayers.METERS_PER_INCH,GunterChain:20.11684023368047/OpenLayers.METERS_PER_INCH,BenoitChain:20.116782494375872/OpenLayers.METERS_PER_INCH,SearsChain:20.11676512155/OpenLayers.METERS_PER_INCH,ClarkeLink:0.201166194976/OpenLayers.METERS_PER_INCH,GunterLink:0.2011684023368047/OpenLayers.METERS_PER_INCH,BenoitLink:0.20116782494375873/OpenLayers.METERS_PER_INCH,
SearsLink:0.2011676512155/OpenLayers.METERS_PER_INCH,Rod:5.02921005842012/OpenLayers.METERS_PER_INCH,IntnlChain:20.1168/OpenLayers.METERS_PER_INCH,IntnlLink:0.201168/OpenLayers.METERS_PER_INCH,Perch:5.02921005842012/OpenLayers.METERS_PER_INCH,Pole:5.02921005842012/OpenLayers.METERS_PER_INCH,Furlong:201.1684023368046/OpenLayers.METERS_PER_INCH,Rood:3.778266898/OpenLayers.METERS_PER_INCH,CapeFoot:0.3047972615/OpenLayers.METERS_PER_INCH,Brealey:375/OpenLayers.METERS_PER_INCH,ModAmFt:0.304812252984506/
OpenLayers.METERS_PER_INCH,Fathom:1.8288/OpenLayers.METERS_PER_INCH,"NautM-UK":1853.184/OpenLayers.METERS_PER_INCH,"50kilometers":5E4/OpenLayers.METERS_PER_INCH,"150kilometers":15E4/OpenLayers.METERS_PER_INCH});
OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{mm:OpenLayers.INCHES_PER_UNIT.Meter/1E3,cm:OpenLayers.INCHES_PER_UNIT.Meter/100,dm:100*OpenLayers.INCHES_PER_UNIT.Meter,km:1E3*OpenLayers.INCHES_PER_UNIT.Meter,kmi:OpenLayers.INCHES_PER_UNIT.nmi,fath:OpenLayers.INCHES_PER_UNIT.Fathom,ch:OpenLayers.INCHES_PER_UNIT.IntnlChain,link:OpenLayers.INCHES_PER_UNIT.IntnlLink,"us-in":OpenLayers.INCHES_PER_UNIT.inches,"us-ft":OpenLayers.INCHES_PER_UNIT.Foot,"us-yd":OpenLayers.INCHES_PER_UNIT.Yard,"us-ch":OpenLayers.INCHES_PER_UNIT.GunterChain,
"us-mi":OpenLayers.INCHES_PER_UNIT.Mile,"ind-yd":OpenLayers.INCHES_PER_UNIT.IndianYd37,"ind-ft":OpenLayers.INCHES_PER_UNIT.IndianFt37,"ind-ch":20.11669506/OpenLayers.METERS_PER_INCH});OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(a){return 1<a?1/a:a};OpenLayers.Util.getResolutionFromScale=function(a,b){var c;a&&(null==b&&(b="degrees"),c=1/(OpenLayers.Util.normalizeScale(a)*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH));return c};
OpenLayers.Util.getScaleFromResolution=function(a,b){null==b&&(b="degrees");return a*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH};
OpenLayers.Util.pagePosition=function(a){var b=[0,0],c=OpenLayers.Util.getViewportElement();if(!a||a==window||a==c)return b;var d=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&"absolute"==OpenLayers.Element.getStyle(a,"position")&&(""==a.style.top||""==a.style.left),e=null;if(a.getBoundingClientRect)a=a.getBoundingClientRect(),e=window.pageYOffset||c.scrollTop,b[0]=a.left+(window.pageXOffset||c.scrollLeft),b[1]=a.top+e;else if(document.getBoxObjectFor&&!d)a=document.getBoxObjectFor(a),c=document.getBoxObjectFor(c),
b[0]=a.screenX-c.screenX,b[1]=a.screenY-c.screenY;else{b[0]=a.offsetLeft;b[1]=a.offsetTop;e=a.offsetParent;if(e!=a)for(;e;)b[0]+=e.offsetLeft,b[1]+=e.offsetTop,e=e.offsetParent;c=OpenLayers.BROWSER_NAME;if("opera"==c||"safari"==c&&"absolute"==OpenLayers.Element.getStyle(a,"position"))b[1]-=document.body.offsetTop;for(e=a.offsetParent;e&&e!=document.body;){b[0]-=e.scrollLeft;if("opera"!=c||"TR"!=e.tagName)b[1]-=e.scrollTop;e=e.offsetParent}}return b};
OpenLayers.Util.getViewportElement=function(){var a=arguments.callee.viewportElement;void 0==a&&(a="msie"==OpenLayers.BROWSER_NAME&&"CSS1Compat"!=document.compatMode?document.body:document.documentElement,arguments.callee.viewportElement=a);return a};
OpenLayers.Util.isEquivalentUrl=function(a,b,c){c=c||{};OpenLayers.Util.applyDefaults(c,{ignoreCase:!0,ignorePort80:!0,ignoreHash:!0,splitArgs:!1});a=OpenLayers.Util.createUrlObject(a,c);b=OpenLayers.Util.createUrlObject(b,c);for(var d in a)if("args"!==d&&a[d]!=b[d])return!1;for(d in a.args){if(a.args[d]!=b.args[d])return!1;delete b.args[d]}for(d in b.args)return!1;return!0};
OpenLayers.Util.createUrlObject=function(a,b){b=b||{};if(!/^\w+:\/\//.test(a)){var c=window.location,d=c.port?":"+c.port:"",d=c.protocol+"//"+c.host.split(":").shift()+d;0===a.indexOf("/")?a=d+a:(c=c.pathname.split("/"),c.pop(),a=d+c.join("/")+"/"+a)}b.ignoreCase&&(a=a.toLowerCase());c=document.createElement("a");c.href=a;d={};d.host=c.host.split(":").shift();d.protocol=c.protocol;d.port=b.ignorePort80?"80"==c.port||"0"==c.port?"":c.port:""==c.port||"0"==c.port?"80":c.port;d.hash=b.ignoreHash||"#"===
c.hash?"":c.hash;var e=c.search;e||(e=a.indexOf("?"),e=-1!=e?a.substr(e):"");d.args=OpenLayers.Util.getParameters(e,{splitArgs:b.splitArgs});d.pathname="/"==c.pathname.charAt(0)?c.pathname:"/"+c.pathname;return d};OpenLayers.Util.removeTail=function(a){var b=null,b=a.indexOf("?"),c=a.indexOf("#");return b=-1==b?-1!=c?a.substr(0,c):a:-1!=c?a.substr(0,Math.min(b,c)):a.substr(0,b)};OpenLayers.IS_GECKO=function(){var a=navigator.userAgent.toLowerCase();return-1==a.indexOf("webkit")&&-1!=a.indexOf("gecko")}();
OpenLayers.CANVAS_SUPPORTED=function(){var a=document.createElement("canvas");return!(!a.getContext||!a.getContext("2d"))}();OpenLayers.BROWSER_NAME=function(){var a="",b=navigator.userAgent.toLowerCase();-1!=b.indexOf("opera")?a="opera":-1!=b.indexOf("msie")?a="msie":-1!=b.indexOf("safari")?a="safari":-1!=b.indexOf("mozilla")&&(a=-1!=b.indexOf("firefox")?"firefox":"mozilla");return a}();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME};
OpenLayers.Util.getRenderedDimensions=function(a,b,c){var d,e,f=document.createElement("div");f.style.visibility="hidden";for(var g=c&&c.containerElement?c.containerElement:document.body,h=!1,k=null,l=g;l&&"body"!=l.tagName.toLowerCase();){var m=OpenLayers.Element.getStyle(l,"position");if("absolute"==m){h=!0;break}else if(m&&"static"!=m)break;l=l.parentNode}!h||0!==g.clientHeight&&0!==g.clientWidth||(k=document.createElement("div"),k.style.visibility="hidden",k.style.position="absolute",k.style.overflow=
"visible",k.style.width=document.body.clientWidth+"px",k.style.height=document.body.clientHeight+"px",k.appendChild(f));f.style.position="absolute";b&&(b.w?(d=b.w,f.style.width=d+"px"):b.h&&(e=b.h,f.style.height=e+"px"));c&&c.displayClass&&(f.className=c.displayClass);b=document.createElement("div");b.innerHTML=a;b.style.overflow="visible";if(b.childNodes)for(a=0,c=b.childNodes.length;a<c;a++)b.childNodes[a].style&&(b.childNodes[a].style.overflow="visible");f.appendChild(b);k?g.appendChild(k):g.appendChild(f);
d||(d=parseInt(b.scrollWidth),f.style.width=d+"px");e||(e=parseInt(b.scrollHeight));f.removeChild(b);k?(k.removeChild(f),g.removeChild(k)):g.removeChild(f);return new OpenLayers.Size(d,e)};
OpenLayers.Util.getScrollbarWidth=function(){var a=OpenLayers.Util._scrollbarWidth;if(null==a){var b=null,c=null,b=a=0,b=document.createElement("div");b.style.position="absolute";b.style.top="-1000px";b.style.left="-1000px";b.style.width="100px";b.style.height="50px";b.style.overflow="hidden";c=document.createElement("div");c.style.width="100%";c.style.height="200px";b.appendChild(c);document.body.appendChild(b);a=c.offsetWidth;b.style.overflow="scroll";b=c.offsetWidth;document.body.removeChild(document.body.lastChild);
OpenLayers.Util._scrollbarWidth=a-b;a=OpenLayers.Util._scrollbarWidth}return a};
OpenLayers.Util.getFormattedLonLat=function(a,b,c){c||(c="dms");a=(a+540)%360-180;var d=Math.abs(a),e=Math.floor(d),f=d=(d-e)/(1/60),d=Math.floor(d),f=Math.round(10*((f-d)/(1/60))),f=f/10;60<=f&&(f-=60,d+=1,60<=d&&(d-=60,e+=1));10>e&&(e="0"+e);e+="\u00b0";0<=c.indexOf("dm")&&(10>d&&(d="0"+d),e+=d+"'",0<=c.indexOf("dms")&&(10>f&&(f="0"+f),e+=f+'"'));return e="lon"==b?e+(0>a?OpenLayers.i18n("W"):OpenLayers.i18n("E")):e+(0>a?OpenLayers.i18n("S"):OpenLayers.i18n("N"))};OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:!1,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a},destroy:function(){},read:function(a){throw Error("Read not implemented.");},write:function(a){throw Error("Write not implemented.");},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Format.CSWGetRecords=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.CSWGetRecords.DEFAULTS);var b=OpenLayers.Format.CSWGetRecords["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSWGetRecords version: "+a.version;return new b(a)};OpenLayers.Format.CSWGetRecords.DEFAULTS={version:"2.0.2"};OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,allowSelection:!1,displayClass:"",title:"",autoActivate:!1,active:null,handlerOptions:null,handler:null,eventListeners:null,events:null,initialize:function(a){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object)this.events.on(this.eventListeners);null==this.id&&(this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+
"_"))},destroy:function(){this.events&&(this.eventListeners&&this.events.un(this.eventListeners),this.events.destroy(),this.events=null);this.eventListeners=null;this.handler&&(this.handler.destroy(),this.handler=null);if(this.handlers){for(var a in this.handlers)this.handlers.hasOwnProperty(a)&&"function"==typeof this.handlers[a].destroy&&this.handlers[a].destroy();this.handlers=null}this.map&&(this.map.removeControl(this),this.map=null);this.div=null},setMap:function(a){this.map=a;this.handler&&
this.handler.setMap(a)},draw:function(a){null==this.div&&(this.div=OpenLayers.Util.createDiv(this.id),this.div.className=this.displayClass,this.allowSelection||(this.div.className+=" olControlNoSelect",this.div.setAttribute("unselectable","on",0),this.div.onselectstart=OpenLayers.Function.False),""!=this.title&&(this.div.title=this.title));null!=a&&(this.position=a.clone());this.moveTo(this.position);return this.div},moveTo:function(a){null!=a&&null!=this.div&&(this.div.style.left=a.x+"px",this.div.style.top=
a.y+"px")},activate:function(){if(this.active)return!1;this.handler&&this.handler.activate();this.active=!0;this.map&&OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");this.events.triggerEvent("activate");return!0},deactivate:function(){return this.active?(this.handler&&this.handler.deactivate(),this.active=!1,this.map&&OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active"),this.events.triggerEvent("deactivate"),
!0):!1},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Event={observers:!1,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&1==a.touches.length},isMultiTouch:function(a){return a.touches&&1<a.touches.length},isLeftClick:function(a){return a.which&&1==a.which||a.button&&1==a.button},isRightClick:function(a){return a.which&&3==a.which||a.button&&2==a.button},stop:function(a,
b){b||OpenLayers.Event.preventDefault(a);a.stopPropagation?a.stopPropagation():a.cancelBubble=!0},preventDefault:function(a){a.preventDefault?a.preventDefault():a.returnValue=!1},findElement:function(a,b){for(var c=OpenLayers.Event.element(a);c.parentNode&&(!c.tagName||c.tagName.toUpperCase()!=b.toUpperCase());)c=c.parentNode;return c},observe:function(a,b,c,d){a=OpenLayers.Util.getElement(a);d=d||!1;"keypress"==b&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.attachEvent)&&(b="keydown");
this.observers||(this.observers={});if(!a._eventCacheID){var e="eventCacheID_";a.id&&(e=a.id+"_"+e);a._eventCacheID=OpenLayers.Util.createUniqueID(e)}e=a._eventCacheID;this.observers[e]||(this.observers[e]=[]);this.observers[e].push({element:a,name:b,observer:c,useCapture:d});a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},stopObservingElement:function(a){a=OpenLayers.Util.getElement(a)._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[a])},
_removeElementObservers:function(a){if(a)for(var b=a.length-1;0<=b;b--){var c=a[b];OpenLayers.Event.stopObserving.apply(this,[c.element,c.name,c.observer,c.useCapture])}},stopObserving:function(a,b,c,d){d=d||!1;a=OpenLayers.Util.getElement(a);var e=a._eventCacheID;"keypress"==b&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.detachEvent)&&(b="keydown");var f=!1,g=OpenLayers.Event.observers[e];if(g)for(var h=0;!f&&h<g.length;){var k=g[h];if(k.name==b&&k.observer==c&&k.useCapture==d){g.splice(h,
1);0==g.length&&delete OpenLayers.Event.observers[e];f=!0;break}h++}f&&(a.removeEventListener?a.removeEventListener(b,c,d):a&&a.detachEvent&&a.detachEvent("on"+b,c));return f},unloadCache:function(){if(OpenLayers.Event&&OpenLayers.Event.observers){for(var a in OpenLayers.Event.observers)OpenLayers.Event._removeElementObservers.apply(this,[OpenLayers.Event.observers[a]]);OpenLayers.Event.observers=!1}},CLASS_NAME:"OpenLayers.Event"};
OpenLayers.Event.observe(window,"unload",OpenLayers.Event.unloadCache,!1);
OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:"mouseover mouseout mousedown mouseup mousemove click dblclick rightclick dblrightclick resize focus blur touchstart touchmove touchend keydown".split(" "),listeners:null,object:null,element:null,eventHandler:null,fallThrough:null,includeXY:!1,extensions:null,extensionCount:null,clearMouseListener:null,initialize:function(a,b,c,d,e){OpenLayers.Util.extend(this,e);this.object=a;this.fallThrough=d;this.listeners={};this.extensions={};this.extensionCount=
{};this._msTouches=[];null!=b&&this.attachToElement(b)},destroy:function(){for(var a in this.extensions)"boolean"!==typeof this.extensions[a]&&this.extensions[a].destroy();this.extensions=null;this.element&&(OpenLayers.Event.stopObservingElement(this.element),this.element.hasScrollEvent&&OpenLayers.Event.stopObserving(window,"scroll",this.clearMouseListener));this.eventHandler=this.fallThrough=this.object=this.listeners=this.element=null},addEventType:function(a){},attachToElement:function(a){this.element?
OpenLayers.Event.stopObservingElement(this.element):(this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this),this.clearMouseListener=OpenLayers.Function.bind(this.clearMouseCache,this));this.element=a;for(var b=!!window.navigator.msMaxTouchPoints,c,d=0,e=this.BROWSER_EVENTS.length;d<e;d++)c=this.BROWSER_EVENTS[d],OpenLayers.Event.observe(a,c,this.eventHandler),b&&0===c.indexOf("touch")&&this.addMsTouchListener(a,c,this.eventHandler);OpenLayers.Event.observe(a,"dragstart",
OpenLayers.Event.stop)},on:function(a){for(var b in a)"scope"!=b&&a.hasOwnProperty(b)&&this.register(b,a.scope,a[b])},register:function(a,b,c,d){a in OpenLayers.Events&&!this.extensions[a]&&(this.extensions[a]=new OpenLayers.Events[a](this));if(null!=c){null==b&&(b=this.object);var e=this.listeners[a];e||(e=[],this.listeners[a]=e,this.extensionCount[a]=0);b={obj:b,func:c};d?(e.splice(this.extensionCount[a],0,b),"object"===typeof d&&d.extension&&this.extensionCount[a]++):e.push(b)}},registerPriority:function(a,
b,c){this.register(a,b,c,!0)},un:function(a){for(var b in a)"scope"!=b&&a.hasOwnProperty(b)&&this.unregister(b,a.scope,a[b])},unregister:function(a,b,c){null==b&&(b=this.object);a=this.listeners[a];if(null!=a)for(var d=0,e=a.length;d<e;d++)if(a[d].obj==b&&a[d].func==c){a.splice(d,1);break}},remove:function(a){null!=this.listeners[a]&&(this.listeners[a]=[])},triggerEvent:function(a,b){var c=this.listeners[a];if(c&&0!=c.length){null==b&&(b={});b.object=this.object;b.element=this.element;b.type||(b.type=
a);for(var c=c.slice(),d,e=0,f=c.length;e<f&&(d=c[e],d=d.func.apply(d.obj,[b]),void 0==d||!1!=d);e++);this.fallThrough||OpenLayers.Event.stop(b,!0);return d}},handleBrowserEvent:function(a){var b=a.type,c=this.listeners[b];if(c&&0!=c.length){if((c=a.touches)&&c[0]){for(var d=0,e=0,f=c.length,g,h=0;h<f;++h)g=this.getTouchClientXY(c[h]),d+=g.clientX,e+=g.clientY;a.clientX=d/f;a.clientY=e/f}this.includeXY&&(a.xy=this.getMousePosition(a));this.triggerEvent(b,a)}},getTouchClientXY:function(a){var b=window.olMockWin||
window,c=b.pageXOffset,b=b.pageYOffset,d=a.clientX,e=a.clientY;if(0===a.pageY&&Math.floor(e)>Math.floor(a.pageY)||0===a.pageX&&Math.floor(d)>Math.floor(a.pageX))d-=c,e-=b;else if(e<a.pageY-b||d<a.pageX-c)d=a.pageX-c,e=a.pageY-b;a.olClientX=d;a.olClientY=e;return{clientX:d,clientY:e}},clearMouseCache:function(){this.element.scrolls=null;this.element.lefttop=null;this.element.offsets=null},getMousePosition:function(a){this.includeXY?this.element.hasScrollEvent||(OpenLayers.Event.observe(window,"scroll",
this.clearMouseListener),this.element.hasScrollEvent=!0):this.clearMouseCache();if(!this.element.scrolls){var b=OpenLayers.Util.getViewportElement();this.element.scrolls=[window.pageXOffset||b.scrollLeft,window.pageYOffset||b.scrollTop]}this.element.lefttop||(this.element.lefttop=[document.documentElement.clientLeft||0,document.documentElement.clientTop||0]);this.element.offsets||(this.element.offsets=OpenLayers.Util.pagePosition(this.element));return new OpenLayers.Pixel(a.clientX+this.element.scrolls[0]-
this.element.offsets[0]-this.element.lefttop[0],a.clientY+this.element.scrolls[1]-this.element.offsets[1]-this.element.lefttop[1])},addMsTouchListener:function(a,b,c){function d(a){c(OpenLayers.Util.applyDefaults({stopPropagation:function(){for(var a=e.length-1;0<=a;--a)e[a].stopPropagation()},preventDefault:function(){for(var a=e.length-1;0<=a;--a)e[a].preventDefault()},type:b},a))}var e=this._msTouches;switch(b){case "touchstart":return this.addMsTouchListenerStart(a,b,d);case "touchend":return this.addMsTouchListenerEnd(a,
b,d);case "touchmove":return this.addMsTouchListenerMove(a,b,d);default:throw"Unknown touch event type";}},addMsTouchListenerStart:function(a,b,c){var d=this._msTouches;OpenLayers.Event.observe(a,"MSPointerDown",function(a){for(var b=!1,g=0,h=d.length;g<h;++g)if(d[g].pointerId==a.pointerId){b=!0;break}b||d.push(a);a.touches=d.slice();c(a)});OpenLayers.Event.observe(a,"MSPointerUp",function(a){for(var b=0,c=d.length;b<c;++b)if(d[b].pointerId==a.pointerId){d.splice(b,1);break}})},addMsTouchListenerMove:function(a,
b,c){var d=this._msTouches;OpenLayers.Event.observe(a,"MSPointerMove",function(a){if(a.pointerType!=a.MSPOINTER_TYPE_MOUSE||0!=a.buttons)if(1!=d.length||d[0].pageX!=a.pageX||d[0].pageY!=a.pageY){for(var b=0,g=d.length;b<g;++b)if(d[b].pointerId==a.pointerId){d[b]=a;break}a.touches=d.slice();c(a)}})},addMsTouchListenerEnd:function(a,b,c){var d=this._msTouches;OpenLayers.Event.observe(a,"MSPointerUp",function(a){for(var b=0,g=d.length;b<g;++b)if(d[b].pointerId==a.pointerId){d.splice(b,1);break}a.touches=
d.slice();c(a)})},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Events.buttonclick=OpenLayers.Class({target:null,events:"mousedown mouseup click dblclick touchstart touchmove touchend keydown".split(" "),startRegEx:/^mousedown|touchstart$/,cancelRegEx:/^touchmove$/,completeRegEx:/^mouseup|touchend$/,initialize:function(a){this.target=a;for(a=this.events.length-1;0<=a;--a)this.target.register(this.events[a],this,this.buttonClick,{extension:!0})},destroy:function(){for(var a=this.events.length-1;0<=a;--a)this.target.unregister(this.events[a],this,this.buttonClick);
delete this.target},getPressedButton:function(a){var b=3,c;do{if(OpenLayers.Element.hasClass(a,"olButton")){c=a;break}a=a.parentNode}while(0<--b&&a);return c},ignore:function(a){var b=3,c=!1;do{if("a"===a.nodeName.toLowerCase()){c=!0;break}a=a.parentNode}while(0<--b&&a);return c},buttonClick:function(a){var b=!0,c=OpenLayers.Event.element(a);if(c&&(OpenLayers.Event.isLeftClick(a)||!~a.type.indexOf("mouse")))if(c=this.getPressedButton(c)){if("keydown"===a.type)switch(a.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick",
{buttonElement:c}),OpenLayers.Event.stop(a),b=!1}else if(this.startEvt){if(this.completeRegEx.test(a.type)){var b=OpenLayers.Util.pagePosition(c),d=OpenLayers.Util.getViewportElement(),e=window.pageYOffset||d.scrollTop;b[0]-=window.pageXOffset||d.scrollLeft;b[1]-=e;this.target.triggerEvent("buttonclick",{buttonElement:c,buttonXY:{x:this.startEvt.clientX-b[0],y:this.startEvt.clientY-b[1]}})}this.cancelRegEx.test(a.type)&&delete this.startEvt;OpenLayers.Event.stop(a);b=!1}this.startRegEx.test(a.type)&&
(this.startEvt=a,OpenLayers.Event.stop(a),b=!1)}else b=!this.ignore(OpenLayers.Event.element(a)),delete this.startEvt;return b}});OpenLayers.Util=OpenLayers.Util||{};
OpenLayers.Util.vendorPrefix=function(){function a(a){return a?a.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()}).replace(/^ms-/,"-ms-"):null}function b(a,b){if(void 0===g[b]){var c,e=0,f=d.length,p="undefined"!==typeof a.cssText;for(g[b]=null;e<f;e++)if((c=d[e])?(p||(c=c.toLowerCase()),c=c+b.charAt(0).toUpperCase()+b.slice(1)):c=b,void 0!==a[c]){g[b]=c;break}}return g[b]}function c(a){return b(e,a)}var d=["","O","ms","Moz","Webkit"],e=document.createElement("div").style,f={},g={};return{css:function(b){if(void 0===
f[b]){var d=b.replace(/(-[\s\S])/g,function(a){return a.charAt(1).toUpperCase()}),d=c(d);f[b]=a(d)}return f[b]},js:b,style:c,cssCache:f,jsCache:g}}();OpenLayers.Animation=function(a){var b=OpenLayers.Util.vendorPrefix.js(a,"requestAnimationFrame"),c=!!b,d=function(){var c=a[b]||function(b,c){a.setTimeout(b,16)};return function(b,d){c.apply(a,[b,d])}}(),e=0,f={};return{isNative:c,requestFrame:d,start:function(a,b,c){b=0<b?b:Number.POSITIVE_INFINITY;var l=++e,m=+new Date;f[l]=function(){f[l]&&+new Date-m<=b?(a(),f[l]&&d(f[l],c)):delete f[l]};d(f[l],c);return l},stop:function(a){delete f[a]}}}(window);OpenLayers.Tween=OpenLayers.Class({easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,minFrameRate:null,startTime:null,animationId:null,playing:!1,initialize:function(a){this.easing=a?a:OpenLayers.Easing.Expo.easeOut},start:function(a,b,c,d){this.playing=!0;this.begin=a;this.finish=b;this.duration=c;this.callbacks=d.callbacks;this.minFrameRate=d.minFrameRate||30;this.time=0;this.startTime=(new Date).getTime();OpenLayers.Animation.stop(this.animationId);this.animationId=null;
this.callbacks&&this.callbacks.start&&this.callbacks.start.call(this,this.begin);this.animationId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.play,this))},stop:function(){this.playing&&(this.callbacks&&this.callbacks.done&&this.callbacks.done.call(this,this.finish),OpenLayers.Animation.stop(this.animationId),this.animationId=null,this.playing=!1)},play:function(){var a={},b;for(b in this.begin){var c=this.begin[b],d=this.finish[b];if(null==c||null==d||isNaN(c)||isNaN(d))throw new TypeError("invalid value for Tween");
a[b]=this.easing.apply(this,[this.time,c,d-c,this.duration])}this.time++;this.callbacks&&this.callbacks.eachStep&&((new Date).getTime()-this.startTime)/this.time<=1E3/this.minFrameRate&&this.callbacks.eachStep.call(this,a);this.time>this.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"};
OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return 0==a?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){return 0==a?b:a==d?b+c:1>(a/=d/2)?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"};
OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){return 1>(a/=d/2)?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,titleRegEx:/\+title=[^\+]*/,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.projCode=a;"object"==typeof Proj4js&&(this.proj=new Proj4js.Proj(a))},getCode:function(){return this.proj?this.proj.srsCode:this.projCode},getUnits:function(){return this.proj?this.proj.units:null},toString:function(){return this.getCode()},equals:function(a){var b=!1;a&&(a instanceof OpenLayers.Projection||(a=new OpenLayers.Projection(a)),"object"==
typeof Proj4js&&this.proj.defData&&a.proj.defData?b=this.proj.defData.replace(this.titleRegEx,"")==a.proj.defData.replace(this.titleRegEx,""):a.getCode&&(b=this.getCode(),a=a.getCode(),b=b==a||!!OpenLayers.Projection.transforms[b]&&OpenLayers.Projection.transforms[b][a]===OpenLayers.Projection.nullTransform));return b},destroy:function(){delete this.proj;delete this.projCode},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};
OpenLayers.Projection.defaults={"EPSG:4326":{units:"degrees",maxExtent:[-180,-90,180,90],yx:!0},"CRS:84":{units:"degrees",maxExtent:[-180,-90,180,90]},"EPSG:900913":{units:"m",maxExtent:[-2.003750834E7,-2.003750834E7,2.003750834E7,2.003750834E7]}};
OpenLayers.Projection.addTransform=function(a,b,c){if(c===OpenLayers.Projection.nullTransform){var d=OpenLayers.Projection.defaults[a];d&&!OpenLayers.Projection.defaults[b]&&(OpenLayers.Projection.defaults[b]=d)}OpenLayers.Projection.transforms[a]||(OpenLayers.Projection.transforms[a]={});OpenLayers.Projection.transforms[a][b]=c};
OpenLayers.Projection.transform=function(a,b,c){if(b&&c)if(b instanceof OpenLayers.Projection||(b=new OpenLayers.Projection(b)),c instanceof OpenLayers.Projection||(c=new OpenLayers.Projection(c)),b.proj&&c.proj)a=Proj4js.transform(b.proj,c.proj,a);else{b=b.getCode();c=c.getCode();var d=OpenLayers.Projection.transforms;if(d[b]&&d[b][c])d[b][c](a)}return a};OpenLayers.Projection.nullTransform=function(a){return a};
(function(){function a(a){a.x=180*a.x/d;a.y=180/Math.PI*(2*Math.atan(Math.exp(a.y/d*Math.PI))-Math.PI/2);return a}function b(a){a.x=a.x*d/180;var b=Math.log(Math.tan((90+a.y)*Math.PI/360))/Math.PI*d;a.y=Math.max(-2.003750834E7,Math.min(b,2.003750834E7));return a}function c(c,d){var e=OpenLayers.Projection.addTransform,f=OpenLayers.Projection.nullTransform,g,p,q,r,s;g=0;for(p=d.length;g<p;++g)for(q=d[g],e(c,q,b),e(q,c,a),s=g+1;s<p;++s)r=d[s],e(q,r,f),e(r,q,f)}var d=2.003750834E7,e=["EPSG:900913","EPSG:3857",
"EPSG:102113","EPSG:102100"],f=["CRS:84","urn:ogc:def:crs:EPSG:6.6:4326","EPSG:4326"],g;for(g=e.length-1;0<=g;--g)c(e[g],f);for(g=f.length-1;0<=g;--g)c(f[g],e)})();OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1E3},id:null,fractionalZoom:!1,events:null,allOverlays:!1,div:null,dragging:!1,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,panRatio:1.5,options:null,tileSize:null,projection:"EPSG:4326",units:null,resolutions:null,maxResolution:null,minResolution:null,maxScale:null,minScale:null,
maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:!1,autoUpdateSize:!0,eventListeners:null,panTween:null,panMethod:OpenLayers.Easing.Expo.easeOut,panDuration:50,zoomTween:null,zoomMethod:OpenLayers.Easing.Quad.easeOut,zoomDuration:20,paddingForPopups:null,layerContainerOriginPx:null,minPx:null,maxPx:null,initialize:function(a,b){1===arguments.length&&"object"===typeof a&&(a=(b=a)&&b.div);this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
OpenLayers.Map.TILE_HEIGHT);this.paddingForPopups=new OpenLayers.Bounds(15,15,15,15);this.theme=OpenLayers._getScriptLocation()+"theme/default/style.css";this.options=OpenLayers.Util.extend({},b);OpenLayers.Util.extend(this,b);OpenLayers.Util.applyDefaults(this,OpenLayers.Projection.defaults[this.projection instanceof OpenLayers.Projection?this.projection.projCode:this.projection]);!this.maxExtent||this.maxExtent instanceof OpenLayers.Bounds||(this.maxExtent=new OpenLayers.Bounds(this.maxExtent));
!this.minExtent||this.minExtent instanceof OpenLayers.Bounds||(this.minExtent=new OpenLayers.Bounds(this.minExtent));!this.restrictedExtent||this.restrictedExtent instanceof OpenLayers.Bounds||(this.restrictedExtent=new OpenLayers.Bounds(this.restrictedExtent));!this.center||this.center instanceof OpenLayers.LonLat||(this.center=new OpenLayers.LonLat(this.center));this.layers=[];this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(a);this.div||(this.div=document.createElement("div"),
this.div.style.height="1px",this.div.style.width="1px");OpenLayers.Element.addClass(this.div,"olMap");var c=this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(c,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);this.events=new OpenLayers.Events(this,this.viewPortDiv,null,this.fallThrough,{includeXY:!0});OpenLayers.TileManager&&null!==
this.tileManager&&(this.tileManager instanceof OpenLayers.TileManager||(this.tileManager=new OpenLayers.TileManager(this.tileManager)),this.tileManager.addMap(this));c=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(c);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE.Popup-1;this.layerContainerOriginPx={x:0,y:0};this.applyTransform();this.viewPortDiv.appendChild(this.layerContainerDiv);this.updateSize();if(this.eventListeners instanceof Object)this.events.on(this.eventListeners);
!0===this.autoUpdateSize&&(this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this),OpenLayers.Event.observe(window,"resize",this.updateSizeDestroy));if(this.theme){for(var c=!0,d=document.getElementsByTagName("link"),e=0,f=d.length;e<f;++e)if(OpenLayers.Util.isEquivalentUrl(d.item(e).href,this.theme)){c=!1;break}c&&(c=document.createElement("link"),c.setAttribute("rel","stylesheet"),c.setAttribute("type","text/css"),c.setAttribute("href",this.theme),document.getElementsByTagName("head")[0].appendChild(c))}null==
this.controls&&(this.controls=[],null!=OpenLayers.Control&&(OpenLayers.Control.Navigation?this.controls.push(new OpenLayers.Control.Navigation):OpenLayers.Control.TouchNavigation&&this.controls.push(new OpenLayers.Control.TouchNavigation),OpenLayers.Control.Zoom?this.controls.push(new OpenLayers.Control.Zoom):OpenLayers.Control.PanZoom&&this.controls.push(new OpenLayers.Control.PanZoom),OpenLayers.Control.ArgParser&&this.controls.push(new OpenLayers.Control.ArgParser),OpenLayers.Control.Attribution&&
this.controls.push(new OpenLayers.Control.Attribution)));e=0;for(f=this.controls.length;e<f;e++)this.addControlToMap(this.controls[e]);this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,"unload",this.unloadDestroy);b&&b.layers&&(delete this.center,delete this.zoom,this.addLayers(b.layers),b.center&&!this.getCenter()&&this.setCenter(b.center,b.zoom));this.panMethod&&(this.panTween=new OpenLayers.Tween(this.panMethod));this.zoomMethod&&this.applyTransform.transform&&
(this.zoomTween=new OpenLayers.Tween(this.zoomMethod))},getViewport:function(){return this.viewPortDiv},render:function(a){this.div=OpenLayers.Util.getElement(a);OpenLayers.Element.addClass(this.div,"olMap");this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);this.div.appendChild(this.viewPortDiv);this.updateSize()},unloadDestroy:null,updateSizeDestroy:null,destroy:function(){if(!this.unloadDestroy)return!1;this.panTween&&(this.panTween.stop(),this.panTween=null);this.zoomTween&&(this.zoomTween.stop(),
this.zoomTween=null);OpenLayers.Event.stopObserving(window,"unload",this.unloadDestroy);this.unloadDestroy=null;this.updateSizeDestroy&&OpenLayers.Event.stopObserving(window,"resize",this.updateSizeDestroy);this.paddingForPopups=null;if(null!=this.controls){for(var a=this.controls.length-1;0<=a;--a)this.controls[a].destroy();this.controls=null}if(null!=this.layers){for(a=this.layers.length-1;0<=a;--a)this.layers[a].destroy(!1);this.layers=null}this.viewPortDiv&&this.viewPortDiv.parentNode&&this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
this.viewPortDiv=null;this.tileManager&&(this.tileManager.removeMap(this),this.tileManager=null);this.eventListeners&&(this.events.un(this.eventListeners),this.eventListeners=null);this.events.destroy();this.options=this.events=null},setOptions:function(a){var b=this.minPx&&a.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,a);b&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:!0})},getTileSize:function(){return this.tileSize},getBy:function(a,b,c){var d="function"==
typeof c.test;return OpenLayers.Array.filter(this[a],function(a){return a[b]==c||d&&c.test(a[b])})},getLayersBy:function(a,b){return this.getBy("layers",a,b)},getLayersByName:function(a){return this.getLayersBy("name",a)},getLayersByClass:function(a){return this.getLayersBy("CLASS_NAME",a)},getControlsBy:function(a,b){return this.getBy("controls",a,b)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},getLayer:function(a){for(var b=null,c=0,d=this.layers.length;c<d;c++){var e=
this.layers[c];if(e.id==a){b=e;break}}return b},setLayerZIndex:function(a,b){a.setZIndex(this.Z_INDEX_BASE[a.isBaseLayer?"BaseLayer":"Overlay"]+5*b)},resetLayersZIndex:function(){for(var a=0,b=this.layers.length;a<b;a++)this.setLayerZIndex(this.layers[a],a)},addLayer:function(a){for(var b=0,c=this.layers.length;b<c;b++)if(this.layers[b]==a)return!1;if(!1===this.events.triggerEvent("preaddlayer",{layer:a}))return!1;this.allOverlays&&(a.isBaseLayer=!1);a.div.className="olLayerDiv";a.div.style.overflow=
"";this.setLayerZIndex(a,this.layers.length);a.isFixed?this.viewPortDiv.appendChild(a.div):this.layerContainerDiv.appendChild(a.div);this.layers.push(a);a.setMap(this);a.isBaseLayer||this.allOverlays&&!this.baseLayer?null==this.baseLayer?this.setBaseLayer(a):a.setVisibility(!1):a.redraw();this.events.triggerEvent("addlayer",{layer:a});a.events.triggerEvent("added",{map:this,layer:a});a.afterAdd();return!0},addLayers:function(a){for(var b=0,c=a.length;b<c;b++)this.addLayer(a[b])},removeLayer:function(a,
b){if(!1!==this.events.triggerEvent("preremovelayer",{layer:a})){null==b&&(b=!0);a.isFixed?this.viewPortDiv.removeChild(a.div):this.layerContainerDiv.removeChild(a.div);OpenLayers.Util.removeItem(this.layers,a);a.removeMap(this);a.map=null;if(this.baseLayer==a&&(this.baseLayer=null,b))for(var c=0,d=this.layers.length;c<d;c++){var e=this.layers[c];if(e.isBaseLayer||this.allOverlays){this.setBaseLayer(e);break}}this.resetLayersZIndex();this.events.triggerEvent("removelayer",{layer:a});a.events.triggerEvent("removed",
{map:this,layer:a})}},getNumLayers:function(){return this.layers.length},getLayerIndex:function(a){return OpenLayers.Util.indexOf(this.layers,a)},setLayerIndex:function(a,b){var c=this.getLayerIndex(a);0>b?b=0:b>this.layers.length&&(b=this.layers.length);if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);for(var c=0,d=this.layers.length;c<d;c++)this.setLayerZIndex(this.layers[c],c);this.events.triggerEvent("changelayer",{layer:a,property:"order"});this.allOverlays&&(0===b?this.setBaseLayer(a):
this.baseLayer!==this.layers[0]&&this.setBaseLayer(this.layers[0]))}},raiseLayer:function(a,b){var c=this.getLayerIndex(a)+b;this.setLayerIndex(a,c)},setBaseLayer:function(a){if(a!=this.baseLayer&&-1!=OpenLayers.Util.indexOf(this.layers,a)){var b=this.getCachedCenter(),c=OpenLayers.Util.getResolutionFromScale(this.getScale(),a.units);null==this.baseLayer||this.allOverlays||this.baseLayer.setVisibility(!1);this.baseLayer=a;if(!this.allOverlays||this.baseLayer.visibility)this.baseLayer.setVisibility(!0),
!1===this.baseLayer.inRange&&this.baseLayer.redraw();null!=b&&(a=this.getZoomForResolution(c||this.resolution,!0),this.setCenter(b,a,!1,!0));this.events.triggerEvent("changebaselayer",{layer:this.baseLayer})}},addControl:function(a,b){this.controls.push(a);this.addControlToMap(a,b)},addControls:function(a,b){for(var c=1===arguments.length?[]:b,d=0,e=a.length;d<e;d++)this.addControl(a[d],c[d]?c[d]:null)},addControlToMap:function(a,b){a.outsideViewport=null!=a.div;this.displayProjection&&!a.displayProjection&&
(a.displayProjection=this.displayProjection);a.setMap(this);var c=a.draw(b);c&&!a.outsideViewport&&(c.style.zIndex=this.Z_INDEX_BASE.Control+this.controls.length,this.viewPortDiv.appendChild(c));a.autoActivate&&a.activate()},getControl:function(a){for(var b=null,c=0,d=this.controls.length;c<d;c++){var e=this.controls[c];if(e.id==a){b=e;break}}return b},removeControl:function(a){a&&a==this.getControl(a.id)&&(a.div&&a.div.parentNode==this.viewPortDiv&&this.viewPortDiv.removeChild(a.div),OpenLayers.Util.removeItem(this.controls,
a))},addPopup:function(a,b){if(b)for(var c=this.popups.length-1;0<=c;--c)this.removePopup(this.popups[c]);a.map=this;this.popups.push(a);if(c=a.draw())c.style.zIndex=this.Z_INDEX_BASE.Popup+this.popups.length,this.layerContainerDiv.appendChild(c)},removePopup:function(a){OpenLayers.Util.removeItem(this.popups,a);if(a.div)try{this.layerContainerDiv.removeChild(a.div)}catch(b){}a.map=null},getSize:function(){var a=null;null!=this.size&&(a=this.size.clone());return a},updateSize:function(){var a=this.getCurrentSize();
if(a&&!isNaN(a.h)&&!isNaN(a.w)){this.events.clearMouseCache();var b=this.getSize();null==b&&(this.size=b=a);if(!a.equals(b)){this.size=a;a=0;for(b=this.layers.length;a<b;a++)this.layers[a].onMapResize();a=this.getCachedCenter();null!=this.baseLayer&&null!=a&&(b=this.getZoom(),this.zoom=null,this.setCenter(a,b))}}this.events.triggerEvent("updatesize")},getCurrentSize:function(){var a=new OpenLayers.Size(this.div.clientWidth,this.div.clientHeight);if(0==a.w&&0==a.h||isNaN(a.w)&&isNaN(a.h))a.w=this.div.offsetWidth,
a.h=this.div.offsetHeight;if(0==a.w&&0==a.h||isNaN(a.w)&&isNaN(a.h))a.w=parseInt(this.div.style.width),a.h=parseInt(this.div.style.height);return a},calculateBounds:function(a,b){var c=null;null==a&&(a=this.getCachedCenter());null==b&&(b=this.getResolution());if(null!=a&&null!=b)var c=this.size.w*b/2,d=this.size.h*b/2,c=new OpenLayers.Bounds(a.lon-c,a.lat-d,a.lon+c,a.lat+d);return c},getCenter:function(){var a=null,b=this.getCachedCenter();b&&(a=b.clone());return a},getCachedCenter:function(){!this.center&&
this.size&&(this.center=this.getLonLatFromViewPortPx({x:this.size.w/2,y:this.size.h/2}));return this.center},getZoom:function(){return this.zoom},pan:function(a,b,c){c=OpenLayers.Util.applyDefaults(c,{animate:!0,dragging:!1});if(c.dragging)0==a&&0==b||this.moveByPx(a,b);else{var d=this.getViewPortPxFromLonLat(this.getCachedCenter());a=d.add(a,b);if(this.dragging||!a.equals(d))d=this.getLonLatFromViewPortPx(a),c.animate?this.panTo(d):(this.moveTo(d),this.dragging&&(this.dragging=!1,this.events.triggerEvent("moveend")))}},
panTo:function(a){if(this.panTween&&this.getExtent().scale(this.panRatio).containsLonLat(a)){var b=this.getCachedCenter();if(!a.equals(b)){var b=this.getPixelFromLonLat(b),c=this.getPixelFromLonLat(a),d=0,e=0;this.panTween.start({x:0,y:0},{x:c.x-b.x,y:c.y-b.y},this.panDuration,{callbacks:{eachStep:OpenLayers.Function.bind(function(a){this.moveByPx(a.x-d,a.y-e);d=Math.round(a.x);e=Math.round(a.y)},this),done:OpenLayers.Function.bind(function(b){this.moveTo(a);this.dragging=!1;this.events.triggerEvent("moveend")},
this)}})}}else this.setCenter(a)},setCenter:function(a,b,c,d){this.panTween&&this.panTween.stop();this.zoomTween&&this.zoomTween.stop();this.moveTo(a,b,{dragging:c,forceZoomChange:d})},moveByPx:function(a,b){var c=this.size.w/2,d=this.size.h/2,e=c+a,f=d+b,g=this.baseLayer.wrapDateLine,h=0,k=0;this.restrictedExtent&&(h=c,k=d,g=!1);a=g||e<=this.maxPx.x-h&&e>=this.minPx.x+h?Math.round(a):0;b=f<=this.maxPx.y-k&&f>=this.minPx.y+k?Math.round(b):0;if(a||b){this.dragging||(this.dragging=!0,this.events.triggerEvent("movestart"));
this.center=null;a&&(this.layerContainerOriginPx.x-=a,this.minPx.x-=a,this.maxPx.x-=a);b&&(this.layerContainerOriginPx.y-=b,this.minPx.y-=b,this.maxPx.y-=b);this.applyTransform();d=0;for(e=this.layers.length;d<e;++d)c=this.layers[d],c.visibility&&(c===this.baseLayer||c.inRange)&&(c.moveByPx(a,b),c.events.triggerEvent("move"));this.events.triggerEvent("move")}},adjustZoom:function(a){if(this.baseLayer&&this.baseLayer.wrapDateLine){var b=this.baseLayer.resolutions,c=this.getMaxExtent().getWidth()/this.size.w;
if(this.getResolutionForZoom(a)>c)if(this.fractionalZoom)a=this.getZoomForResolution(c);else for(var d=a|0,e=b.length;d<e;++d)if(b[d]<=c){a=d;break}}return a},getMinZoom:function(){return this.adjustZoom(0)},moveTo:function(a,b,c){null==a||a instanceof OpenLayers.LonLat||(a=new OpenLayers.LonLat(a));c||(c={});null!=b&&(b=parseFloat(b),this.fractionalZoom||(b=Math.round(b)));var d=b;b=this.adjustZoom(b);b!==d&&(a=this.getCenter());var d=c.dragging||this.dragging,e=c.forceZoomChange;this.getCachedCenter()||
this.isValidLonLat(a)||(a=this.maxExtent.getCenterLonLat(),this.center=a.clone());if(null!=this.restrictedExtent){null==a&&(a=this.center);null==b&&(b=this.getZoom());var f=this.getResolutionForZoom(b),f=this.calculateBounds(a,f);if(!this.restrictedExtent.containsBounds(f)){var g=this.restrictedExtent.getCenterLonLat();f.getWidth()>this.restrictedExtent.getWidth()?a=new OpenLayers.LonLat(g.lon,a.lat):f.left<this.restrictedExtent.left?a=a.add(this.restrictedExtent.left-f.left,0):f.right>this.restrictedExtent.right&&
(a=a.add(this.restrictedExtent.right-f.right,0));f.getHeight()>this.restrictedExtent.getHeight()?a=new OpenLayers.LonLat(a.lon,g.lat):f.bottom<this.restrictedExtent.bottom?a=a.add(0,this.restrictedExtent.bottom-f.bottom):f.top>this.restrictedExtent.top&&(a=a.add(0,this.restrictedExtent.top-f.top))}}e=e||this.isValidZoomLevel(b)&&b!=this.getZoom();f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart",{zoomChanged:e});f&&(!e&&this.center&&this.centerLayerContainer(a),
this.center=a.clone());a=e?this.getResolutionForZoom(b):this.getResolution();if(e||null==this.layerContainerOrigin){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerOriginPx.x=0;this.layerContainerOriginPx.y=0;this.applyTransform();var f=this.getMaxExtent({restricted:!0}),h=f.getCenterLonLat(),g=this.center.lon-h.lon,h=h.lat-this.center.lat,k=Math.round(f.getWidth()/a),l=Math.round(f.getHeight()/a);this.minPx={x:(this.size.w-k)/2-g/a,y:(this.size.h-l)/2-h/a};this.maxPx={x:this.minPx.x+
Math.round(f.getWidth()/a),y:this.minPx.y+Math.round(f.getHeight()/a)}}e&&(this.zoom=b,this.resolution=a);a=this.getExtent();this.baseLayer.visibility&&(this.baseLayer.moveTo(a,e,c.dragging),c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e}));a=this.baseLayer.getExtent();for(b=this.layers.length-1;0<=b;--b)f=this.layers[b],f===this.baseLayer||f.isBaseLayer||(g=f.calculateInRange(),f.inRange!=g&&((f.inRange=g)||f.display(!1),this.events.triggerEvent("changelayer",{layer:f,property:"visibility"})),
g&&f.visibility&&(f.moveTo(a,e,c.dragging),c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e})));this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b<c;b++)this.popups[b].updatePosition();this.events.triggerEvent("zoomend")}}},centerLayerContainer:function(a){var b=this.getViewPortPxFromLonLat(this.layerContainerOrigin),c=this.getViewPortPxFromLonLat(a);if(null!=b&&null!=c){var d=this.layerContainerOriginPx.x;a=this.layerContainerOriginPx.y;
var e=Math.round(b.x-c.x),b=Math.round(b.y-c.y);this.applyTransform(this.layerContainerOriginPx.x=e,this.layerContainerOriginPx.y=b);d-=e;a-=b;this.minPx.x-=d;this.maxPx.x-=d;this.minPx.y-=a;this.maxPx.y-=a}},isValidZoomLevel:function(a){return null!=a&&0<=a&&a<this.getNumZoomLevels()},isValidLonLat:function(a){var b=!1;null!=a&&(b=this.getMaxExtent(),b=b.containsLonLat(a,{worldBounds:this.baseLayer.wrapDateLine&&b}));return b},getProjection:function(){var a=this.getProjectionObject();return a?a.getCode():
null},getProjectionObject:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.projection);return a},getMaxResolution:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.maxResolution);return a},getMaxExtent:function(a){var b=null;a&&a.restricted&&this.restrictedExtent?b=this.restrictedExtent:null!=this.baseLayer&&(b=this.baseLayer.maxExtent);return b},getNumZoomLevels:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.numZoomLevels);return a},getExtent:function(){var a=
null;null!=this.baseLayer&&(a=this.baseLayer.getExtent());return a},getResolution:function(){var a=null;null!=this.baseLayer?a=this.baseLayer.getResolution():!0===this.allOverlays&&0<this.layers.length&&(a=this.layers[0].getResolution());return a},getUnits:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.units);return a},getScale:function(){var a=null;null!=this.baseLayer&&(a=this.getResolution(),a=OpenLayers.Util.getScaleFromResolution(a,this.baseLayer.units));return a},getZoomForExtent:function(a,
b){var c=null;null!=this.baseLayer&&(c=this.baseLayer.getZoomForExtent(a,b));return c},getResolutionForZoom:function(a){var b=null;this.baseLayer&&(b=this.baseLayer.getResolutionForZoom(a));return b},getZoomForResolution:function(a,b){var c=null;null!=this.baseLayer&&(c=this.baseLayer.getZoomForResolution(a,b));return c},zoomTo:function(a,b){var c=this;if(c.isValidZoomLevel(a))if(c.baseLayer.wrapDateLine&&(a=c.adjustZoom(a)),c.zoomTween){var d=c.getResolution(),e=c.getResolutionForZoom(a),f={scale:1},
d={scale:d/e};c.zoomTween.playing&&c.zoomTween.duration<3*c.zoomDuration?c.zoomTween.finish={scale:c.zoomTween.finish.scale*d.scale}:(b||(e=c.getSize(),b={x:e.w/2,y:e.h/2}),c.zoomTween.start(f,d,c.zoomDuration,{minFrameRate:50,callbacks:{eachStep:function(a){var d=c.layerContainerOriginPx;a=a.scale;c.applyTransform(d.x+((a-1)*(d.x-b.x)|0),d.y+((a-1)*(d.y-b.y)|0),a)},done:function(a){c.applyTransform();a=c.getResolution()/a.scale;var d=c.getZoomForResolution(a,!0);c.moveTo(c.getZoomTargetCenter(b,
a),d,!0)}}}))}else f=b?c.getZoomTargetCenter(b,c.getResolutionForZoom(a)):null,c.setCenter(f,a)},zoomIn:function(){this.zoomTo(this.getZoom()+1)},zoomOut:function(){this.zoomTo(this.getZoom()-1)},zoomToExtent:function(a,b){a instanceof OpenLayers.Bounds||(a=new OpenLayers.Bounds(a));var c=a.getCenterLonLat();if(this.baseLayer.wrapDateLine){c=this.getMaxExtent();for(a=a.clone();a.right<a.left;)a.right+=c.getWidth();c=a.getCenterLonLat().wrapDateLine(c)}this.setCenter(c,this.getZoomForExtent(a,b))},
zoomToMaxExtent:function(a){a=this.getMaxExtent({restricted:a?a.restricted:!0});this.zoomToExtent(a)},zoomToScale:function(a,b){var c=OpenLayers.Util.getResolutionFromScale(a,this.baseLayer.units),d=this.size.w*c/2,c=this.size.h*c/2,e=this.getCachedCenter(),d=new OpenLayers.Bounds(e.lon-d,e.lat-c,e.lon+d,e.lat+c);this.zoomToExtent(d,b)},getLonLatFromViewPortPx:function(a){var b=null;null!=this.baseLayer&&(b=this.baseLayer.getLonLatFromViewPortPx(a));return b},getViewPortPxFromLonLat:function(a){var b=
null;null!=this.baseLayer&&(b=this.baseLayer.getViewPortPxFromLonLat(a));return b},getZoomTargetCenter:function(a,b){var c=null,d=this.getSize(),e=d.w/2-a.x,d=a.y-d.h/2,f=this.getLonLatFromPixel(a);f&&(c=new OpenLayers.LonLat(f.lon+e*b,f.lat+d*b));return c},getLonLatFromPixel:function(a){return this.getLonLatFromViewPortPx(a)},getPixelFromLonLat:function(a){a=this.getViewPortPxFromLonLat(a);a.x=Math.round(a.x);a.y=Math.round(a.y);return a},getGeodesicPixelSize:function(a){var b=a?this.getLonLatFromPixel(a):
this.getCachedCenter()||new OpenLayers.LonLat(0,0),c=this.getResolution();a=b.add(-c/2,0);var d=b.add(c/2,0),e=b.add(0,-c/2),b=b.add(0,c/2),c=new OpenLayers.Projection("EPSG:4326"),f=this.getProjectionObject()||c;f.equals(c)||(a.transform(f,c),d.transform(f,c),e.transform(f,c),b.transform(f,c));return new OpenLayers.Size(OpenLayers.Util.distVincenty(a,d),OpenLayers.Util.distVincenty(e,b))},getViewPortPxFromLayerPx:function(a){var b=null;null!=a&&(b=a.add(this.layerContainerOriginPx.x,this.layerContainerOriginPx.y));
return b},getLayerPxFromViewPortPx:function(a){var b=null;null!=a&&(b=a.add(-this.layerContainerOriginPx.x,-this.layerContainerOriginPx.y),isNaN(b.x)||isNaN(b.y))&&(b=null);return b},getLonLatFromLayerPx:function(a){a=this.getViewPortPxFromLayerPx(a);return this.getLonLatFromViewPortPx(a)},getLayerPxFromLonLat:function(a){a=this.getPixelFromLonLat(a);return this.getLayerPxFromViewPortPx(a)},applyTransform:function(a,b,c){c=c||1;var d=this.layerContainerOriginPx,e=1!==c;a=a||d.x;b=b||d.y;var f=this.layerContainerDiv.style,
g=this.applyTransform.transform,h=this.applyTransform.template;if(void 0===g&&(g=OpenLayers.Util.vendorPrefix.style("transform"),this.applyTransform.transform=g)){var k=OpenLayers.Element.getStyle(this.viewPortDiv,OpenLayers.Util.vendorPrefix.css("transform"));k&&"none"===k||(h=["translate3d(",",0) ","scale3d(",",1)"],f[g]=[h[0],"0,0",h[1]].join(""));h&&~f[g].indexOf(h[0])||(h=["translate(",") ","scale(",")"]);this.applyTransform.template=h}null===g||"translate3d("!==h[0]&&!0!==e?(f.left=a+"px",f.top=
b+"px",null!==g&&(f[g]="")):(!0===e&&"translate("===h[0]&&(a-=d.x,b-=d.y,f.left=d.x+"px",f.top=d.y+"px"),f[g]=[h[0],a,"px,",b,"px",h[1],h[2],c,",",c,h[3]].join(""))},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:!1,evt:null,touch:!1,initialize:function(a,b,c){OpenLayers.Util.extend(this,c);this.control=a;this.callbacks=b;(a=this.map||a.map)&&this.setMap(a);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},setMap:function(a){this.map=a},checkModifiers:function(a){return null==this.keyMask?!0:((a.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(a.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(a.altKey?OpenLayers.Handler.MOD_ALT:
0)|(a.metaKey?OpenLayers.Handler.MOD_META:0))==this.keyMask},activate:function(){if(this.active)return!1;for(var a=OpenLayers.Events.prototype.BROWSER_EVENTS,b=0,c=a.length;b<c;b++)this[a[b]]&&this.register(a[b],this[a[b]]);return this.active=!0},deactivate:function(){if(!this.active)return!1;for(var a=OpenLayers.Events.prototype.BROWSER_EVENTS,b=0,c=a.length;b<c;b++)this[a[b]]&&this.unregister(a[b],this[a[b]]);this.active=this.touch=!1;return!0},startTouch:function(){if(!this.touch){this.touch=!0;
for(var a="mousedown mouseup mousemove click dblclick mouseout".split(" "),b=0,c=a.length;b<c;b++)this[a[b]]&&this.unregister(a[b],this[a[b]])}},callback:function(a,b){a&&this.callbacks[a]&&this.callbacks[a].apply(this.control,b)},register:function(a,b){this.map.events.registerPriority(a,this,b);this.map.events.registerPriority(a,this,this.setEvent)},unregister:function(a,b){this.map.events.unregister(a,this,b);this.map.events.unregister(a,this,this.setEvent)},setEvent:function(a){this.evt=a;return!0},
destroy:function(){this.deactivate();this.control=this.map=null},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Handler.MOD_META=8;OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:!0,"double":!1,pixelTolerance:0,dblclickTolerance:13,stopSingle:!1,stopDouble:!1,timerId:null,down:null,last:null,first:null,rightclickTimerId:null,touchstart:function(a){this.startTouch();this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return!0},touchmove:function(a){this.last=this.getEventInfo(a);return!0},touchend:function(a){this.down&&(a.xy=this.last.xy,a.lastTouches=this.last.touches,this.handleSingle(a),
this.down=null);return!0},mousedown:function(a){this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return!0},mouseup:function(a){var b=!0;this.checkModifiers(a)&&(this.control.handleRightClicks&&OpenLayers.Event.isRightClick(a))&&(b=this.rightclick(a));return b},rightclick:function(a){if(this.passesTolerance(a)){if(null!=this.rightclickTimerId)return this.clearTimer(),this.callback("dblrightclick",[a]),!this.stopDouble;a=this["double"]?OpenLayers.Util.extend({},a):this.callback("rightclick",
[a]);a=OpenLayers.Function.bind(this.delayedRightCall,this,a);this.rightclickTimerId=window.setTimeout(a,this.delay)}return!this.stopSingle},delayedRightCall:function(a){this.rightclickTimerId=null;a&&this.callback("rightclick",[a])},click:function(a){this.last||(this.last=this.getEventInfo(a));this.handleSingle(a);return!this.stopSingle},dblclick:function(a){this.handleDouble(a);return!this.stopDouble},handleDouble:function(a){this.passesDblclickTolerance(a)&&(this["double"]&&this.callback("dblclick",
[a]),this.clearTimer())},handleSingle:function(a){this.passesTolerance(a)&&(null!=this.timerId?(this.last.touches&&1===this.last.touches.length&&(this["double"]&&OpenLayers.Event.preventDefault(a),this.handleDouble(a)),this.last.touches&&2===this.last.touches.length||this.clearTimer()):(this.first=this.getEventInfo(a),a=this.single?OpenLayers.Util.extend({},a):null,this.queuePotentialClick(a)))},queuePotentialClick:function(a){this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,
this,a),this.delay)},passesTolerance:function(a){var b=!0;if(null!=this.pixelTolerance&&this.down&&this.down.xy&&(b=this.pixelTolerance>=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length){a=0;for(var c=this.down.touches.length;a<c;++a)if(this.getTouchDistance(this.down.touches[a],this.last.touches[a])>this.pixelTolerance){b=!1;break}}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,
2))},passesDblclickTolerance:function(a){a=!0;this.down&&this.first&&(a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance);return a},clearTimer:function(){null!=this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null);null!=this.rightclickTimerId&&(window.clearTimeout(this.rightclickTimerId),this.rightclickTimerId=null)},delayedCall:function(a){this.timerId=null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,
e=0;e<c;e++)d=a.touches[e],b[e]={clientX:d.olClientX,clientY:d.olClientY}}return{xy:a.xy,touches:b}},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.clearTimer(),this.last=this.first=this.down=null,a=!0);return a},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!0,dragging:!1,last:null,start:null,lastMoveEvt:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:!1,documentEvents:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(!0===this.documentDrag){var d=this;this._docMove=function(a){d.mousemove({xy:{x:a.clientX,y:a.clientY},element:document})};this._docUp=function(a){d.mouseup({xy:{x:a.clientX,y:a.clientY}})}}},
dragstart:function(a){var b=!0;this.dragging=!1;this.checkModifiers(a)&&(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))?(this.started=!0,this.last=this.start=a.xy,OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown"),this.down(a),this.callback("down",[a.xy]),OpenLayers.Event.preventDefault(a),this.oldOnselectstart||(this.oldOnselectstart=document.onselectstart?document.onselectstart:OpenLayers.Function.True),document.onselectstart=OpenLayers.Function.False,b=!this.stopDown):
(this.started=!1,this.last=this.start=null);return b},dragmove:function(a){this.lastMoveEvt=a;!this.started||(this.timeoutId||a.xy.x==this.last.x&&a.xy.y==this.last.y)||(!0===this.documentDrag&&this.documentEvents&&(a.element===document?(this.adjustXY(a),this.setEvent(a)):this.removeDocumentEvents()),0<this.interval&&(this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval)),this.dragging=!0,this.move(a),this.callback("move",[a.xy]),this.oldOnselectstart||(this.oldOnselectstart=
document.onselectstart,document.onselectstart=OpenLayers.Function.False),this.last=a.xy);return!0},dragend:function(a){if(this.started){!0===this.documentDrag&&this.documentEvents&&(this.adjustXY(a),this.removeDocumentEvents());var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(a);this.callback("up",[a.xy]);b&&this.callback("done",[a.xy]);document.onselectstart=this.oldOnselectstart}return!0},down:function(a){},move:function(a){},
up:function(a){},out:function(a){},mousedown:function(a){return this.dragstart(a)},touchstart:function(a){this.startTouch();return this.dragstart(a)},mousemove:function(a){return this.dragmove(a)},touchmove:function(a){return this.dragmove(a)},removeTimeout:function(){this.timeoutId=null;this.dragging&&this.mousemove(this.lastMoveEvt)},mouseup:function(a){return this.dragend(a)},touchend:function(a){a.xy=this.last;return this.dragend(a)},mouseout:function(a){if(this.started&&OpenLayers.Util.mouseLeft(a,
this.map.viewPortDiv))if(!0===this.documentDrag)this.addDocumentEvents();else{var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(a);this.callback("out",[]);b&&this.callback("done",[a.xy]);document.onselectstart&&(document.onselectstart=this.oldOnselectstart)}return!0},click:function(a){return this.start==this.last},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.dragging=
!1,a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.dragging=this.started=!1,this.last=this.start=null,a=!0,OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown"));return a},adjustXY:function(a){var b=OpenLayers.Util.pagePosition(this.map.viewPortDiv);a.xy.x-=b[0];a.xy.y-=b[1]},addDocumentEvents:function(){OpenLayers.Element.addClass(document.body,"olDragDown");this.documentEvents=!0;OpenLayers.Event.observe(document,"mousemove",
this._docMove);OpenLayers.Event.observe(document,"mouseup",this._docUp)},removeDocumentEvents:function(){OpenLayers.Element.removeClass(document.body,"olDragDown");this.documentEvents=!1;OpenLayers.Event.stopObserving(document,"mousemove",this._docMove);OpenLayers.Event.stopObserving(document,"mouseup",this._docUp)},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Control.OverviewMap=OpenLayers.Class(OpenLayers.Control,{element:null,ovmap:null,size:{w:180,h:90},layers:null,minRectSize:15,minRectDisplayClass:"RectReplacement",minRatio:8,maxRatio:32,mapOptions:null,autoPan:!1,handlers:null,resolutionFactor:1,maximized:!1,maximizeTitle:"",minimizeTitle:"",initialize:function(a){this.layers=[];this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,[a])},destroy:function(){this.mapDiv&&(this.handlers.click&&this.handlers.click.destroy(),
this.handlers.drag&&this.handlers.drag.destroy(),this.ovmap&&this.ovmap.viewPortDiv.removeChild(this.extentRectangle),this.extentRectangle=null,this.rectEvents&&(this.rectEvents.destroy(),this.rectEvents=null),this.ovmap&&(this.ovmap.destroy(),this.ovmap=null),this.element.removeChild(this.mapDiv),this.mapDiv=null,this.div.removeChild(this.element),this.element=null,this.maximizeDiv&&(this.div.removeChild(this.maximizeDiv),this.maximizeDiv=null),this.minimizeDiv&&(this.div.removeChild(this.minimizeDiv),
this.minimizeDiv=null),this.map.events.un({buttonclick:this.onButtonClick,moveend:this.update,changebaselayer:this.baseLayerDraw,scope:this}),OpenLayers.Control.prototype.destroy.apply(this,arguments))},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(0===this.layers.length)if(this.map.baseLayer)this.layers=[this.map.baseLayer.clone()];else return this.map.events.register("changebaselayer",this,this.baseLayerDraw),this.div;this.element=document.createElement("div");this.element.className=
this.displayClass+"Element";this.element.style.display="none";this.mapDiv=document.createElement("div");this.mapDiv.style.width=this.size.w+"px";this.mapDiv.style.height=this.size.h+"px";this.mapDiv.style.position="relative";this.mapDiv.style.overflow="hidden";this.mapDiv.id=OpenLayers.Util.createUniqueID("overviewMap");this.extentRectangle=document.createElement("div");this.extentRectangle.style.position="absolute";this.extentRectangle.style.zIndex=1E3;this.extentRectangle.className=this.displayClass+
"ExtentRectangle";this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);if(this.outsideViewport)this.element.style.display="";else{this.div.className+=" "+this.displayClass+"Container";var a=OpenLayers.Util.getImageLocation("layer-switcher-maximize.png");this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv(this.displayClass+"MaximizeButton",null,null,a,"absolute");this.maximizeDiv.style.display="none";this.maximizeDiv.className=this.displayClass+"MaximizeButton olButton";this.maximizeTitle&&
(this.maximizeDiv.title=this.maximizeTitle);this.div.appendChild(this.maximizeDiv);a=OpenLayers.Util.getImageLocation("layer-switcher-minimize.png");this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_minimizeDiv",null,null,a,"absolute");this.minimizeDiv.style.display="none";this.minimizeDiv.className=this.displayClass+"MinimizeButton olButton";this.minimizeTitle&&(this.minimizeDiv.title=this.minimizeTitle);this.div.appendChild(this.minimizeDiv);this.minimizeControl()}this.map.getExtent()&&
this.update();this.map.events.on({buttonclick:this.onButtonClick,moveend:this.update,scope:this});this.maximized&&this.maximizeControl();return this.div},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",this,this.baseLayerDraw)},rectDrag:function(a){var b=this.handlers.drag.last.x-a.x,c=this.handlers.drag.last.y-a.y;if(0!=b||0!=c){var d=this.rectPxBounds.top,e=this.rectPxBounds.left;a=Math.abs(this.rectPxBounds.getHeight());var f=this.rectPxBounds.getWidth(),c=Math.max(0,
d-c),c=Math.min(c,this.ovmap.size.h-this.hComp-a),b=Math.max(0,e-b),b=Math.min(b,this.ovmap.size.w-this.wComp-f);this.setRectPxBounds(new OpenLayers.Bounds(b,c+a,b+f,c))}},mapDivClick:function(a){var b=this.rectPxBounds.getCenterPixel(),c=a.xy.x-b.x,d=a.xy.y-b.y,e=this.rectPxBounds.top,f=this.rectPxBounds.left;a=Math.abs(this.rectPxBounds.getHeight());b=this.rectPxBounds.getWidth();d=Math.max(0,e+d);d=Math.min(d,this.ovmap.size.h-a);c=Math.max(0,f+c);c=Math.min(c,this.ovmap.size.w-b);this.setRectPxBounds(new OpenLayers.Bounds(c,
d+a,c+b,d));this.updateMapToRect()},onButtonClick:function(a){a.buttonElement===this.minimizeDiv?this.minimizeControl():a.buttonElement===this.maximizeDiv&&this.maximizeControl()},maximizeControl:function(a){this.element.style.display="";this.showToggle(!1);null!=a&&OpenLayers.Event.stop(a)},minimizeControl:function(a){this.element.style.display="none";this.showToggle(!0);null!=a&&OpenLayers.Event.stop(a)},showToggle:function(a){this.maximizeDiv&&(this.maximizeDiv.style.display=a?"":"none");this.minimizeDiv&&
(this.minimizeDiv.style.display=a?"none":"")},update:function(){null==this.ovmap&&this.createMap();!this.autoPan&&this.isSuitableOverview()||this.updateOverview();this.updateRectToMap()},isSuitableOverview:function(){var a=this.map.getExtent(),b=this.map.getMaxExtent(),a=new OpenLayers.Bounds(Math.max(a.left,b.left),Math.max(a.bottom,b.bottom),Math.min(a.right,b.right),Math.min(a.top,b.top));this.ovmap.getProjection()!=this.map.getProjection()&&(a=a.transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject()));
b=this.ovmap.getResolution()/this.map.getResolution();return b>this.minRatio&&b<=this.maxRatio&&this.ovmap.getExtent().containsBounds(a)},updateOverview:function(){var a=this.map.getResolution(),b=this.ovmap.getResolution(),c=b/a;c>this.maxRatio?b=this.minRatio*a:c<=this.minRatio&&(b=this.maxRatio*a);this.ovmap.getProjection()!=this.map.getProjection()?(a=this.map.center.clone(),a.transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject())):a=this.map.center;this.ovmap.setCenter(a,
this.ovmap.getZoomForResolution(b*this.resolutionFactor));this.updateRectToMap()},createMap:function(){var a=OpenLayers.Util.extend({controls:[],maxResolution:"auto",fallThrough:!1},this.mapOptions);this.ovmap=new OpenLayers.Map(this.mapDiv,a);this.ovmap.viewPortDiv.appendChild(this.extentRectangle);OpenLayers.Event.stopObserving(window,"unload",this.ovmap.unloadDestroy);this.ovmap.addLayers(this.layers);this.ovmap.zoomToMaxExtent();this.wComp=(this.wComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
"border-left-width"))+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-right-width")))?this.wComp:2;this.hComp=(this.hComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-top-width"))+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-bottom-width")))?this.hComp:2;this.handlers.drag=new OpenLayers.Handler.Drag(this,{move:this.rectDrag,done:this.updateMapToRect},{map:this.ovmap});this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.mapDivClick},
{single:!0,"double":!1,stopSingle:!0,stopDouble:!0,pixelTolerance:1,map:this.ovmap});this.handlers.click.activate();this.rectEvents=new OpenLayers.Events(this,this.extentRectangle,null,!0);this.rectEvents.register("mouseover",this,function(a){this.handlers.drag.active||this.map.dragging||this.handlers.drag.activate()});this.rectEvents.register("mouseout",this,function(a){this.handlers.drag.dragging||this.handlers.drag.deactivate()});if(this.ovmap.getProjection()!=this.map.getProjection()){var a=this.map.getProjectionObject().getUnits()||
this.map.units||this.map.baseLayer.units,b=this.ovmap.getProjectionObject().getUnits()||this.ovmap.units||this.ovmap.baseLayer.units;this.resolutionFactor=a&&b?OpenLayers.INCHES_PER_UNIT[a]/OpenLayers.INCHES_PER_UNIT[b]:1}},updateRectToMap:function(){var a;a=this.ovmap.getProjection()!=this.map.getProjection()?this.map.getExtent().transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject()):this.map.getExtent();(a=this.getRectBoundsFromMapBounds(a))&&this.setRectPxBounds(a)},updateMapToRect:function(){var a=
this.getMapBoundsFromRectBounds(this.rectPxBounds);this.ovmap.getProjection()!=this.map.getProjection()&&(a=a.transform(this.ovmap.getProjectionObject(),this.map.getProjectionObject()));this.map.panTo(a.getCenterLonLat())},setRectPxBounds:function(a){var b=Math.max(a.top,0),c=Math.max(a.left,0),d=Math.min(a.top+Math.abs(a.getHeight()),this.ovmap.size.h-this.hComp);a=Math.min(a.left+a.getWidth(),this.ovmap.size.w-this.wComp);var e=Math.max(a-c,0),f=Math.max(d-b,0);e<this.minRectSize||f<this.minRectSize?
(this.extentRectangle.className=this.displayClass+this.minRectDisplayClass,e=c+e/2-this.minRectSize/2,this.extentRectangle.style.top=Math.round(b+f/2-this.minRectSize/2)+"px",this.extentRectangle.style.left=Math.round(e)+"px",this.extentRectangle.style.height=this.minRectSize+"px",this.extentRectangle.style.width=this.minRectSize+"px"):(this.extentRectangle.className=this.displayClass+"ExtentRectangle",this.extentRectangle.style.top=Math.round(b)+"px",this.extentRectangle.style.left=Math.round(c)+
"px",this.extentRectangle.style.height=Math.round(f)+"px",this.extentRectangle.style.width=Math.round(e)+"px");this.rectPxBounds=new OpenLayers.Bounds(Math.round(c),Math.round(d),Math.round(a),Math.round(b))},getRectBoundsFromMapBounds:function(a){var b=this.getOverviewPxFromLonLat({lon:a.left,lat:a.bottom});a=this.getOverviewPxFromLonLat({lon:a.right,lat:a.top});var c=null;b&&a&&(c=new OpenLayers.Bounds(b.x,b.y,a.x,a.y));return c},getMapBoundsFromRectBounds:function(a){var b=this.getLonLatFromOverviewPx({x:a.left,
y:a.bottom});a=this.getLonLatFromOverviewPx({x:a.right,y:a.top});return new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat)},getLonLatFromOverviewPx:function(a){var b=this.ovmap.size,c=this.ovmap.getResolution(),d=this.ovmap.getExtent().getCenterLonLat();return{lon:d.lon+(a.x-b.w/2)*c,lat:d.lat-(a.y-b.h/2)*c}},getOverviewPxFromLonLat:function(a){var b=this.ovmap.getResolution(),c=this.ovmap.getExtent();if(c)return{x:Math.round(1/b*(a.lon-c.left)),y:Math.round(1/b*(c.top-a.lat))}},CLASS_NAME:"OpenLayers.Control.OverviewMap"});OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,opacity:1,alwaysInRange:null,RESOLUTION_PROPERTIES:"scales resolutions maxScale minScale maxResolution minResolution numZoomLevels maxZoomLevel".split(" "),events:null,map:null,isBaseLayer:!1,alpha:!1,displayInLayerSwitcher:!0,visibility:!0,attribution:null,inRange:!1,imageSize:null,options:null,eventListeners:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null,
numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:!1,wrapDateLine:!1,metadata:null,initialize:function(a,b){this.metadata={};b=OpenLayers.Util.extend({},b);null!=this.alwaysInRange&&(b.alwaysInRange=this.alwaysInRange);this.addOptions(b);this.name=a;if(null==this.id&&(this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_"),this.div=OpenLayers.Util.createDiv(this.id),this.div.style.width="100%",this.div.style.height="100%",this.div.dir="ltr",this.events=new OpenLayers.Events(this,
this.div),this.eventListeners instanceof Object))this.events.on(this.eventListeners)},destroy:function(a){null==a&&(a=!0);null!=this.map&&this.map.removeLayer(this,a);this.options=this.div=this.name=this.map=this.projection=null;this.events&&(this.eventListeners&&this.events.un(this.eventListeners),this.events.destroy());this.events=this.eventListeners=null},clone:function(a){null==a&&(a=new OpenLayers.Layer(this.name,this.getOptions()));OpenLayers.Util.applyDefaults(a,this);a.map=null;return a},
getOptions:function(){var a={},b;for(b in this.options)a[b]=this[b];return a},setName:function(a){a!=this.name&&(this.name=a,null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"name"}))},addOptions:function(a,b){null==this.options&&(this.options={});a&&("string"==typeof a.projection&&(a.projection=new OpenLayers.Projection(a.projection)),a.projection&&OpenLayers.Util.applyDefaults(a,OpenLayers.Projection.defaults[a.projection.getCode()]),!a.maxExtent||a.maxExtent instanceof
OpenLayers.Bounds||(a.maxExtent=new OpenLayers.Bounds(a.maxExtent)),!a.minExtent||a.minExtent instanceof OpenLayers.Bounds||(a.minExtent=new OpenLayers.Bounds(a.minExtent)));OpenLayers.Util.extend(this.options,a);OpenLayers.Util.extend(this,a);this.projection&&this.projection.getUnits()&&(this.units=this.projection.getUnits());if(this.map){var c=this.map.getResolution(),d=this.RESOLUTION_PROPERTIES.concat(["projection","units","minExtent","maxExtent"]),e;for(e in a)if(a.hasOwnProperty(e)&&0<=OpenLayers.Util.indexOf(d,
e)){this.initResolutions();b&&this.map.baseLayer===this&&(this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(c),!1,!0),this.map.events.triggerEvent("changebaselayer",{layer:this}));break}}},onMapResize:function(){},redraw:function(){var a=!1;if(this.map){this.inRange=this.calculateInRange();var b=this.getExtent();b&&(this.inRange&&this.visibility)&&(this.moveTo(b,!0,!1),this.events.triggerEvent("moveend",{zoomChanged:!0}),a=!0)}return a},moveTo:function(a,b,c){a=this.visibility;
this.isBaseLayer||(a=a&&this.inRange);this.display(a)},moveByPx:function(a,b){},setMap:function(a){null==this.map&&(this.map=a,this.maxExtent=this.maxExtent||this.map.maxExtent,this.minExtent=this.minExtent||this.map.minExtent,this.projection=this.projection||this.map.projection,"string"==typeof this.projection&&(this.projection=new OpenLayers.Projection(this.projection)),this.units=this.projection.getUnits()||this.units||this.map.units,this.initResolutions(),this.isBaseLayer||(this.inRange=this.calculateInRange(),
this.div.style.display=this.visibility&&this.inRange?"":"none"),this.setTileSize())},afterAdd:function(){},removeMap:function(a){},getImageSize:function(a){return this.imageSize||this.tileSize},setTileSize:function(a){this.tileSize=a=a?a:this.tileSize?this.tileSize:this.map.getTileSize();this.gutter&&(this.imageSize=new OpenLayers.Size(a.w+2*this.gutter,a.h+2*this.gutter))},getVisibility:function(){return this.visibility},setVisibility:function(a){a!=this.visibility&&(this.visibility=a,this.display(a),
this.redraw(),null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"}),this.events.triggerEvent("visibilitychanged"))},display:function(a){a!=("none"!=this.div.style.display)&&(this.div.style.display=a&&this.calculateInRange()?"block":"none")},calculateInRange:function(){var a=!1;this.alwaysInRange?a=!0:this.map&&(a=this.map.getResolution(),a=a>=this.minResolution&&a<=this.maxResolution);return a},setIsBaseLayer:function(a){a!=this.isBaseLayer&&(this.isBaseLayer=
a,null!=this.map&&this.map.events.triggerEvent("changebaselayer",{layer:this}))},initResolutions:function(){var a,b,c,d={},e=!0;a=0;for(b=this.RESOLUTION_PROPERTIES.length;a<b;a++)c=this.RESOLUTION_PROPERTIES[a],d[c]=this.options[c],e&&this.options[c]&&(e=!1);null==this.options.alwaysInRange&&(this.alwaysInRange=e);null==d.resolutions&&(d.resolutions=this.resolutionsFromScales(d.scales));null==d.resolutions&&(d.resolutions=this.calculateResolutions(d));if(null==d.resolutions){a=0;for(b=this.RESOLUTION_PROPERTIES.length;a<
b;a++)c=this.RESOLUTION_PROPERTIES[a],d[c]=null!=this.options[c]?this.options[c]:this.map[c];null==d.resolutions&&(d.resolutions=this.resolutionsFromScales(d.scales));null==d.resolutions&&(d.resolutions=this.calculateResolutions(d))}var f;this.options.maxResolution&&"auto"!==this.options.maxResolution&&(f=this.options.maxResolution);this.options.minScale&&(f=OpenLayers.Util.getResolutionFromScale(this.options.minScale,this.units));var g;this.options.minResolution&&"auto"!==this.options.minResolution&&
(g=this.options.minResolution);this.options.maxScale&&(g=OpenLayers.Util.getResolutionFromScale(this.options.maxScale,this.units));d.resolutions&&(d.resolutions.sort(function(a,b){return b-a}),f||(f=d.resolutions[0]),g||(g=d.resolutions[d.resolutions.length-1]));if(this.resolutions=d.resolutions){b=this.resolutions.length;this.scales=Array(b);for(a=0;a<b;a++)this.scales[a]=OpenLayers.Util.getScaleFromResolution(this.resolutions[a],this.units);this.numZoomLevels=b}if(this.minResolution=g)this.maxScale=
OpenLayers.Util.getScaleFromResolution(g,this.units);if(this.maxResolution=f)this.minScale=OpenLayers.Util.getScaleFromResolution(f,this.units)},resolutionsFromScales:function(a){if(null!=a){var b,c,d;d=a.length;b=Array(d);for(c=0;c<d;c++)b[c]=OpenLayers.Util.getResolutionFromScale(a[c],this.units);return b}},calculateResolutions:function(a){var b,c,d=a.maxResolution;null!=a.minScale?d=OpenLayers.Util.getResolutionFromScale(a.minScale,this.units):"auto"==d&&null!=this.maxExtent&&(b=this.map.getSize(),
c=this.maxExtent.getWidth()/b.w,b=this.maxExtent.getHeight()/b.h,d=Math.max(c,b));c=a.minResolution;null!=a.maxScale?c=OpenLayers.Util.getResolutionFromScale(a.maxScale,this.units):"auto"==a.minResolution&&null!=this.minExtent&&(b=this.map.getSize(),c=this.minExtent.getWidth()/b.w,b=this.minExtent.getHeight()/b.h,c=Math.max(c,b));"number"!==typeof d&&("number"!==typeof c&&null!=this.maxExtent)&&(d=this.map.getTileSize(),d=Math.max(this.maxExtent.getWidth()/d.w,this.maxExtent.getHeight()/d.h));b=a.maxZoomLevel;
a=a.numZoomLevels;"number"===typeof c&&"number"===typeof d&&void 0===a?a=Math.floor(Math.log(d/c)/Math.log(2))+1:void 0===a&&null!=b&&(a=b+1);if(!("number"!==typeof a||0>=a||"number"!==typeof d&&"number"!==typeof c)){b=Array(a);var e=2;"number"==typeof c&&"number"==typeof d&&(e=Math.pow(d/c,1/(a-1)));var f;if("number"===typeof d)for(f=0;f<a;f++)b[f]=d/Math.pow(e,f);else for(f=0;f<a;f++)b[a-1-f]=c*Math.pow(e,f);return b}},getResolution:function(){var a=this.map.getZoom();return this.getResolutionForZoom(a)},
getExtent:function(){return this.map.calculateBounds()},getZoomForExtent:function(a,b){var c=this.map.getSize(),c=Math.max(a.getWidth()/c.w,a.getHeight()/c.h);return this.getZoomForResolution(c,b)},getDataExtent:function(){},getResolutionForZoom:function(a){a=Math.max(0,Math.min(a,this.resolutions.length-1));if(this.map.fractionalZoom){var b=Math.floor(a),c=Math.ceil(a);a=this.resolutions[b]-(a-b)*(this.resolutions[b]-this.resolutions[c])}else a=this.resolutions[Math.round(a)];return a},getZoomForResolution:function(a,
b){var c,d;if(this.map.fractionalZoom){var e=0,f=this.resolutions[e],g=this.resolutions[this.resolutions.length-1],h;c=0;for(d=this.resolutions.length;c<d;++c)if(h=this.resolutions[c],h>=a&&(f=h,e=c),h<=a){g=h;break}c=f-g;c=0<c?e+(f-a)/c:e}else{f=Number.POSITIVE_INFINITY;c=0;for(d=this.resolutions.length;c<d;c++)if(b){e=Math.abs(this.resolutions[c]-a);if(e>f)break;f=e}else if(this.resolutions[c]<a)break;c=Math.max(0,c-1)}return c},getLonLatFromViewPortPx:function(a){var b=null,c=this.map;if(null!=
a&&c.minPx){var b=c.getResolution(),d=c.getMaxExtent({restricted:!0}),b=new OpenLayers.LonLat((a.x-c.minPx.x)*b+d.left,(c.minPx.y-a.y)*b+d.top);this.wrapDateLine&&(b=b.wrapDateLine(this.maxExtent))}return b},getViewPortPxFromLonLat:function(a,b){var c=null;null!=a&&(b=b||this.map.getResolution(),c=this.map.calculateBounds(null,b),c=new OpenLayers.Pixel(1/b*(a.lon-c.left),1/b*(c.top-a.lat)));return c},setOpacity:function(a){if(a!=this.opacity){this.opacity=a;for(var b=this.div.childNodes,c=0,d=b.length;c<
d;++c){var e=b[c].firstChild||b[c],f=b[c].lastChild;f&&"iframe"===f.nodeName.toLowerCase()&&(e=f.parentNode);OpenLayers.Util.modifyDOMElement(e,null,null,null,null,null,null,a)}null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"})}},getZIndex:function(){return this.div.style.zIndex},setZIndex:function(a){this.div.style.zIndex=a},adjustBounds:function(a){if(this.gutter){var b=this.gutter*this.map.getResolution();a=new OpenLayers.Bounds(a.left-b,a.bottom-b,a.right+
b,a.top+b)}this.wrapDateLine&&(b={rightTolerance:this.getResolution(),leftTolerance:this.getResolution()},a=a.wrapDateLine(this.maxExtent,b));return a},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Layer.SphericalMercator={getExtent:function(){var a=null;return a=this.sphericalMercator?this.map.calculateBounds():OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this)},getLonLatFromViewPortPx:function(a){return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this,arguments)},getViewPortPxFromLonLat:function(a){return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this,arguments)},initMercatorParameters:function(){this.RESOLUTIONS=[];for(var a=0;a<=this.MAX_ZOOM_LEVEL;++a)this.RESOLUTIONS[a]=
156543.03390625/Math.pow(2,a);this.units="m";this.projection=this.projection||"EPSG:900913"},forwardMercator:function(){var a=new OpenLayers.Projection("EPSG:4326"),b=new OpenLayers.Projection("EPSG:900913");return function(c,d){var e=OpenLayers.Projection.transform({x:c,y:d},a,b);return new OpenLayers.LonLat(e.x,e.y)}}(),inverseMercator:function(){var a=new OpenLayers.Projection("EPSG:4326"),b=new OpenLayers.Projection("EPSG:900913");return function(c,d){var e=OpenLayers.Projection.transform({x:c,
y:d},b,a);return new OpenLayers.LonLat(e.x,e.y)}}()};OpenLayers.Layer.EventPane=OpenLayers.Class(OpenLayers.Layer,{smoothDragPan:!0,isBaseLayer:!0,isFixed:!0,pane:null,mapObject:null,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);null==this.pane&&(this.pane=OpenLayers.Util.createDiv(this.div.id+"_EventPane"))},destroy:function(){this.pane=this.mapObject=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Layer.prototype.setMap.apply(this,arguments);this.pane.style.zIndex=
parseInt(this.div.style.zIndex)+1;this.pane.style.display=this.div.style.display;this.pane.style.width="100%";this.pane.style.height="100%";"msie"==OpenLayers.BROWSER_NAME&&(this.pane.style.background="url("+OpenLayers.Util.getImageLocation("blank.gif")+")");this.isFixed?this.map.viewPortDiv.appendChild(this.pane):this.map.layerContainerDiv.appendChild(this.pane);this.loadMapObject();null==this.mapObject&&this.loadWarningMessage()},removeMap:function(a){this.pane&&this.pane.parentNode&&this.pane.parentNode.removeChild(this.pane);
OpenLayers.Layer.prototype.removeMap.apply(this,arguments)},loadWarningMessage:function(){this.div.style.backgroundColor="darkblue";var a=this.map.getSize(),b=Math.min(a.w,300),c=Math.min(a.h,200),b=new OpenLayers.Size(b,c),a=(new OpenLayers.Pixel(a.w/2,a.h/2)).add(-b.w/2,-b.h/2),a=OpenLayers.Util.createDiv(this.name+"_warning",a,b,null,null,null,"auto");a.style.padding="7px";a.style.backgroundColor="yellow";a.innerHTML=this.getWarningHTML();this.div.appendChild(a)},getWarningHTML:function(){return""},
display:function(a){OpenLayers.Layer.prototype.display.apply(this,arguments);this.pane.style.display=this.div.style.display},setZIndex:function(a){OpenLayers.Layer.prototype.setZIndex.apply(this,arguments);this.pane.style.zIndex=parseInt(this.div.style.zIndex)+1},moveByPx:function(a,b){OpenLayers.Layer.prototype.moveByPx.apply(this,arguments);this.dragPanMapObject?this.dragPanMapObject(a,-b):this.moveTo(this.map.getCachedCenter())},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,
arguments);if(null!=this.mapObject){var d=this.map.getCenter(),e=this.map.getZoom();if(null!=d){var f=this.getMapObjectCenter(),f=this.getOLLonLatFromMapObjectLonLat(f),g=this.getMapObjectZoom(),g=this.getOLZoomFromMapObjectZoom(g);d.equals(f)&&e==g||(!b&&f&&this.dragPanMapObject&&this.smoothDragPan?(e=this.map.getViewPortPxFromLonLat(f),d=this.map.getViewPortPxFromLonLat(d),this.dragPanMapObject(d.x-e.x,e.y-d.y)):(d=this.getMapObjectLonLatFromOLLonLat(d),e=this.getMapObjectZoomFromOLZoom(e),this.setMapObjectCenter(d,
e,c)))}}},getLonLatFromViewPortPx:function(a){var b=null;null!=this.mapObject&&null!=this.getMapObjectCenter()&&(a=this.getMapObjectPixelFromOLPixel(a),a=this.getMapObjectLonLatFromMapObjectPixel(a),b=this.getOLLonLatFromMapObjectLonLat(a));return b},getViewPortPxFromLonLat:function(a){var b=null;null!=this.mapObject&&null!=this.getMapObjectCenter()&&(a=this.getMapObjectLonLatFromOLLonLat(a),a=this.getMapObjectPixelFromMapObjectLonLat(a),b=this.getOLPixelFromMapObjectPixel(a));return b},getOLLonLatFromMapObjectLonLat:function(a){var b=
null;null!=a&&(b=this.getLongitudeFromMapObjectLonLat(a),a=this.getLatitudeFromMapObjectLonLat(a),b=new OpenLayers.LonLat(b,a));return b},getMapObjectLonLatFromOLLonLat:function(a){var b=null;null!=a&&(b=this.getMapObjectLonLatFromLonLat(a.lon,a.lat));return b},getOLPixelFromMapObjectPixel:function(a){var b=null;null!=a&&(b=this.getXFromMapObjectPixel(a),a=this.getYFromMapObjectPixel(a),b=new OpenLayers.Pixel(b,a));return b},getMapObjectPixelFromOLPixel:function(a){var b=null;null!=a&&(b=this.getMapObjectPixelFromXY(a.x,
a.y));return b},CLASS_NAME:"OpenLayers.Layer.EventPane"});OpenLayers.Layer.FixedZoomLevels=OpenLayers.Class({initialize:function(){},initResolutions:function(){for(var a=["minZoomLevel","maxZoomLevel","numZoomLevels"],b=0,c=a.length;b<c;b++){var d=a[b];this[d]=null!=this.options[d]?this.options[d]:this.map[d]}if(null==this.minZoomLevel||this.minZoomLevel<this.MIN_ZOOM_LEVEL)this.minZoomLevel=this.MIN_ZOOM_LEVEL;a=this.MAX_ZOOM_LEVEL-this.minZoomLevel+1;b=null==this.options.numZoomLevels&&null!=this.options.maxZoomLevel||null==this.numZoomLevels&&null!=this.maxZoomLevel?
this.maxZoomLevel-this.minZoomLevel+1:this.numZoomLevels;this.numZoomLevels=null!=b?Math.min(b,a):a;this.maxZoomLevel=this.minZoomLevel+this.numZoomLevels-1;if(null!=this.RESOLUTIONS){a=0;this.resolutions=[];for(b=this.minZoomLevel;b<=this.maxZoomLevel;b++)this.resolutions[a++]=this.RESOLUTIONS[b];this.maxResolution=this.resolutions[0];this.minResolution=this.resolutions[this.resolutions.length-1]}},getResolution:function(){if(null!=this.resolutions)return OpenLayers.Layer.prototype.getResolution.apply(this,
arguments);var a=null,b=this.map.getSize(),c=this.getExtent();null!=b&&null!=c&&(a=Math.max(c.getWidth()/b.w,c.getHeight()/b.h));return a},getExtent:function(){var a=this.map.getSize(),b=this.getLonLatFromViewPortPx({x:0,y:0}),a=this.getLonLatFromViewPortPx({x:a.w,y:a.h});return null!=b&&null!=a?new OpenLayers.Bounds(b.lon,a.lat,a.lon,b.lat):null},getZoomForResolution:function(a){if(null!=this.resolutions)return OpenLayers.Layer.prototype.getZoomForResolution.apply(this,arguments);var b=OpenLayers.Layer.prototype.getExtent.apply(this,
[]);return this.getZoomForExtent(b)},getOLZoomFromMapObjectZoom:function(a){var b=null;null!=a&&(b=a-this.minZoomLevel,this.map.baseLayer!==this&&(b=this.map.baseLayer.getZoomForResolution(this.getResolutionForZoom(b))));return b},getMapObjectZoomFromOLZoom:function(a){var b=null;null!=a&&(b=a+this.minZoomLevel,this.map.baseLayer!==this&&(b=this.getZoomForResolution(this.map.baseLayer.getResolutionForZoom(b))));return b},CLASS_NAME:"OpenLayers.Layer.FixedZoomLevels"});OpenLayers.Layer.Google=OpenLayers.Class(OpenLayers.Layer.EventPane,OpenLayers.Layer.FixedZoomLevels,{MIN_ZOOM_LEVEL:0,MAX_ZOOM_LEVEL:21,RESOLUTIONS:[1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,6.866455078125E-4,3.4332275390625E-4,1.71661376953125E-4,8.58306884765625E-5,4.291534423828125E-5,2.145767211914062E-5,1.072883605957031E-5,5.36441802978515E-6,2.68220901489257E-6,1.341104507446289E-6,6.705522537231445E-7],
type:null,wrapDateLine:!0,sphericalMercator:!1,version:null,initialize:function(a,b){b=b||{};b.version||(b.version="function"===typeof GMap2?"2":"3");var c=OpenLayers.Layer.Google["v"+b.version.replace(/\./g,"_")];if(c)OpenLayers.Util.applyDefaults(b,c);else throw"Unsupported Google Maps API version: "+b.version;OpenLayers.Util.applyDefaults(b,c.DEFAULTS);b.maxExtent&&(b.maxExtent=b.maxExtent.clone());OpenLayers.Layer.EventPane.prototype.initialize.apply(this,[a,b]);OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
[a,b]);this.sphericalMercator&&(OpenLayers.Util.extend(this,OpenLayers.Layer.SphericalMercator),this.initMercatorParameters())},clone:function(){return new OpenLayers.Layer.Google(this.name,this.getOptions())},setVisibility:function(a){var b=null==this.opacity?1:this.opacity;OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this,arguments);this.setOpacity(b)},display:function(a){this._dragging||this.setGMapVisibility(a);OpenLayers.Layer.EventPane.prototype.display.apply(this,arguments)},moveTo:function(a,
b,c){this._dragging=c;OpenLayers.Layer.EventPane.prototype.moveTo.apply(this,arguments);delete this._dragging},setOpacity:function(a){a!==this.opacity&&(null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"}),this.opacity=a);if(this.getVisibility()){var b=this.getMapContainer();OpenLayers.Util.modifyDOMElement(b,null,null,null,null,null,null,a)}},destroy:function(){if(this.map){this.setGMapVisibility(!1);var a=OpenLayers.Layer.Google.cache[this.map.id];a&&1>=a.count&&
this.removeGMapElements()}OpenLayers.Layer.EventPane.prototype.destroy.apply(this,arguments)},removeGMapElements:function(){var a=OpenLayers.Layer.Google.cache[this.map.id];if(a){var b=this.mapObject&&this.getMapContainer();b&&b.parentNode&&b.parentNode.removeChild(b);(b=a.termsOfUse)&&b.parentNode&&b.parentNode.removeChild(b);(a=a.poweredBy)&&a.parentNode&&a.parentNode.removeChild(a);this.mapObject&&(window.google&&google.maps&&google.maps.event&&google.maps.event.clearListeners)&&google.maps.event.clearListeners(this.mapObject,
"tilesloaded")}},removeMap:function(a){this.visibility&&this.mapObject&&this.setGMapVisibility(!1);var b=OpenLayers.Layer.Google.cache[a.id];b&&(1>=b.count?(this.removeGMapElements(),delete OpenLayers.Layer.Google.cache[a.id]):--b.count);delete this.termsOfUse;delete this.poweredBy;delete this.mapObject;delete this.dragObject;OpenLayers.Layer.EventPane.prototype.removeMap.apply(this,arguments)},getOLBoundsFromMapObjectBounds:function(a){var b=null;null!=a&&(b=a.getSouthWest(),a=a.getNorthEast(),this.sphericalMercator?
(b=this.forwardMercator(b.lng(),b.lat()),a=this.forwardMercator(a.lng(),a.lat())):(b=new OpenLayers.LonLat(b.lng(),b.lat()),a=new OpenLayers.LonLat(a.lng(),a.lat())),b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat));return b},getWarningHTML:function(){return OpenLayers.i18n("googleWarning")},getMapObjectCenter:function(){return this.mapObject.getCenter()},getMapObjectZoom:function(){return this.mapObject.getZoom()},getLongitudeFromMapObjectLonLat:function(a){return this.sphericalMercator?this.forwardMercator(a.lng(),
a.lat()).lon:a.lng()},getLatitudeFromMapObjectLonLat:function(a){return this.sphericalMercator?this.forwardMercator(a.lng(),a.lat()).lat:a.lat()},getXFromMapObjectPixel:function(a){return a.x},getYFromMapObjectPixel:function(a){return a.y},CLASS_NAME:"OpenLayers.Layer.Google"});OpenLayers.Layer.Google.cache={};
OpenLayers.Layer.Google.v2={termsOfUse:null,poweredBy:null,dragObject:null,loadMapObject:function(){this.type||(this.type=G_NORMAL_MAP);var a,b,c,d=OpenLayers.Layer.Google.cache[this.map.id];if(d)a=d.mapObject,b=d.termsOfUse,c=d.poweredBy,++d.count;else{var d=this.map.viewPortDiv,e=document.createElement("div");e.id=this.map.id+"_GMap2Container";e.style.position="absolute";e.style.width="100%";e.style.height="100%";d.appendChild(e);try{a=new GMap2(e),b=e.lastChild,d.appendChild(b),b.style.zIndex=
"1100",b.style.right="",b.style.bottom="",b.className="olLayerGoogleCopyright",c=e.lastChild,d.appendChild(c),c.style.zIndex="1100",c.style.right="",c.style.bottom="",c.className="olLayerGooglePoweredBy gmnoprint"}catch(f){throw f;}OpenLayers.Layer.Google.cache[this.map.id]={mapObject:a,termsOfUse:b,poweredBy:c,count:1}}this.mapObject=a;this.termsOfUse=b;this.poweredBy=c;-1===OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),this.type)&&this.mapObject.addMapType(this.type);"function"==typeof a.getDragObject?
this.dragObject=a.getDragObject():this.dragPanMapObject=null;!1===this.isBaseLayer&&this.setGMapVisibility("none"!==this.div.style.display)},onMapResize:function(){if(this.visibility&&this.mapObject.isLoaded())this.mapObject.checkResize();else{if(!this._resized)var a=this,b=GEvent.addListener(this.mapObject,"load",function(){GEvent.removeListener(b);delete a._resized;a.mapObject.checkResize();a.moveTo(a.map.getCenter(),a.map.getZoom())});this._resized=!0}},setGMapVisibility:function(a){var b=OpenLayers.Layer.Google.cache[this.map.id];
if(b){var c=this.mapObject.getContainer();!0===a?(this.mapObject.setMapType(this.type),c.style.display="",this.termsOfUse.style.left="",this.termsOfUse.style.display="",this.poweredBy.style.display="",b.displayed=this.id):(b.displayed===this.id&&delete b.displayed,b.displayed||(c.style.display="none",this.termsOfUse.style.display="none",this.termsOfUse.style.left="-9999px",this.poweredBy.style.display="none"))}},getMapContainer:function(){return this.mapObject.getContainer()},getMapObjectBoundsFromOLBounds:function(a){var b=
null;null!=a&&(b=this.sphericalMercator?this.inverseMercator(a.bottom,a.left):new OpenLayers.LonLat(a.bottom,a.left),a=this.sphericalMercator?this.inverseMercator(a.top,a.right):new OpenLayers.LonLat(a.top,a.right),b=new GLatLngBounds(new GLatLng(b.lat,b.lon),new GLatLng(a.lat,a.lon)));return b},setMapObjectCenter:function(a,b){this.mapObject.setCenter(a,b)},dragPanMapObject:function(a,b){this.dragObject.moveBy(new GSize(-a,b))},getMapObjectLonLatFromMapObjectPixel:function(a){return this.mapObject.fromContainerPixelToLatLng(a)},
getMapObjectPixelFromMapObjectLonLat:function(a){return this.mapObject.fromLatLngToContainerPixel(a)},getMapObjectZoomFromMapObjectBounds:function(a){return this.mapObject.getBoundsZoomLevel(a)},getMapObjectLonLatFromLonLat:function(a,b){var c;this.sphericalMercator?(c=this.inverseMercator(a,b),c=new GLatLng(c.lat,c.lon)):c=new GLatLng(b,a);return c},getMapObjectPixelFromXY:function(a,b){return new GPoint(a,b)}};OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(a){window.ActiveXObject&&(this.xmldom=new ActiveXObject("Microsoft.XMLDOM"));OpenLayers.Format.prototype.initialize.apply(this,[a]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var b in this.namespaces)this.namespaceAlias[this.namespaces[b]]=b},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this,
arguments)},setNamespace:function(a,b){this.namespaces[a]=b;this.namespaceAlias[b]=a},read:function(a){var b=a.indexOf("<");0<b&&(a=a.substring(b));b=OpenLayers.Util.Try(OpenLayers.Function.bind(function(){var b;b=window.ActiveXObject&&!this.xmldom?new ActiveXObject("Microsoft.XMLDOM"):this.xmldom;b.loadXML(a);return b},this),function(){return(new DOMParser).parseFromString(a,"text/xml")},function(){var b=new XMLHttpRequest;b.open("GET","data:text/xml;charset=utf-8,"+encodeURIComponent(a),!1);b.overrideMimeType&&
b.overrideMimeType("text/xml");b.send(null);return b.responseXML});this.keepData&&(this.data=b);return b},write:function(a){if(this.xmldom)a=a.xml;else{var b=new XMLSerializer;if(1==a.nodeType){var c=document.implementation.createDocument("","",null);c.importNode&&(a=c.importNode(a,!0));c.appendChild(a);a=b.serializeToString(c)}else a=b.serializeToString(a)}return a},createElementNS:function(a,b){return this.xmldom?"string"==typeof a?this.xmldom.createNode(1,b,a):this.xmldom.createNode(1,b,""):document.createElementNS(a,
b)},createDocumentFragment:function(){return this.xmldom?this.xmldom.createDocumentFragment():document.createDocumentFragment()},createTextNode:function(a){"string"!==typeof a&&(a=String(a));return this.xmldom?this.xmldom.createTextNode(a):document.createTextNode(a)},getElementsByTagNameNS:function(a,b,c){var d=[];if(a.getElementsByTagNameNS)d=a.getElementsByTagNameNS(b,c);else{a=a.getElementsByTagName("*");for(var e,f,g=0,h=a.length;g<h;++g)if(e=a[g],f=e.prefix?e.prefix+":"+c:c,"*"==c||f==e.nodeName)"*"!=
b&&b!=e.namespaceURI||d.push(e)}return d},getAttributeNodeNS:function(a,b,c){var d=null;if(a.getAttributeNodeNS)d=a.getAttributeNodeNS(b,c);else{a=a.attributes;for(var e,f,g=0,h=a.length;g<h;++g)if(e=a[g],e.namespaceURI==b&&(f=e.prefix?e.prefix+":"+c:c,f==e.nodeName)){d=e;break}}return d},getAttributeNS:function(a,b,c){var d="";if(a.getAttributeNS)d=a.getAttributeNS(b,c)||"";else if(a=this.getAttributeNodeNS(a,b,c))d=a.nodeValue;return d},getChildValue:function(a,b){var c=b||"";if(a)for(var d=a.firstChild;d;d=
d.nextSibling)switch(d.nodeType){case 3:case 4:c+=d.nodeValue}return c},isSimpleContent:function(a){var b=!0;for(a=a.firstChild;a;a=a.nextSibling)if(1===a.nodeType){b=!1;break}return b},contentType:function(a){var b=!1,c=!1,d=OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;for(a=a.firstChild;a;a=a.nextSibling){switch(a.nodeType){case 1:c=!0;break;case 8:break;default:b=!0}if(c&&b)break}if(c&&b)d=OpenLayers.Format.XML.CONTENT_TYPE.MIXED;else{if(c)return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;if(b)return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE}return d},
hasAttributeNS:function(a,b,c){var d=!1;return d=a.hasAttributeNS?a.hasAttributeNS(b,c):!!this.getAttributeNodeNS(a,b,c)},setAttributeNS:function(a,b,c,d){if(a.setAttributeNS)a.setAttributeNS(b,c,d);else if(this.xmldom)b?(b=a.ownerDocument.createNode(2,c,b),b.nodeValue=d,a.setAttributeNode(b)):a.setAttribute(c,d);else throw"setAttributeNS not implemented";},createElementNSPlus:function(a,b){b=b||{};var c=b.uri||this.namespaces[b.prefix];c||(c=a.indexOf(":"),c=this.namespaces[a.substring(0,c)]);c||
(c=this.namespaces[this.defaultPrefix]);c=this.createElementNS(c,a);b.attributes&&this.setAttributes(c,b.attributes);var d=b.value;null!=d&&c.appendChild(this.createTextNode(d));return c},setAttributes:function(a,b){var c,d,e;for(e in b)null!=b[e]&&b[e].toString&&(c=b[e].toString(),d=this.namespaces[e.substring(0,e.indexOf(":"))]||null,this.setAttributeNS(a,d,e,c))},readNode:function(a,b){b||(b={});var c=this.readers[a.namespaceURI?this.namespaceAlias[a.namespaceURI]:this.defaultPrefix];if(c){var d=
a.localName||a.nodeName.split(":").pop();(c=c[d]||c["*"])&&c.apply(this,[a,b])}return b},readChildNodes:function(a,b){b||(b={});for(var c=a.childNodes,d,e=0,f=c.length;e<f;++e)d=c[e],1==d.nodeType&&this.readNode(d,b);return b},writeNode:function(a,b,c){var d,e=a.indexOf(":");0<e?(d=a.substring(0,e),a=a.substring(e+1)):d=c?this.namespaceAlias[c.namespaceURI]:this.defaultPrefix;b=this.writers[d][a].apply(this,[b]);c&&c.appendChild(b);return b},getChildEl:function(a,b,c){return a&&this.getThisOrNextEl(a.firstChild,
b,c)},getNextEl:function(a,b,c){return a&&this.getThisOrNextEl(a.nextSibling,b,c)},getThisOrNextEl:function(a,b,c){a:for(;a;a=a.nextSibling)switch(a.nodeType){case 1:if(!(b&&b!==(a.localName||a.nodeName.split(":").pop())||c&&c!==a.namespaceURI))break a;a=null;break a;case 3:if(/^\s*$/.test(a.nodeValue))break;case 4:case 6:case 12:case 10:case 11:a=null;break a}return a||null},lookupNamespaceURI:function(a,b){var c=null;if(a)if(a.lookupNamespaceURI)c=a.lookupNamespaceURI(b);else a:switch(a.nodeType){case 1:if(null!==
a.namespaceURI&&a.prefix===b){c=a.namespaceURI;break a}if(c=a.attributes.length)for(var d,e=0;e<c;++e)if(d=a.attributes[e],"xmlns"===d.prefix&&d.name==="xmlns:"+b){c=d.value||null;break a}else if("xmlns"===d.name&&null===b){c=d.value||null;break a}c=this.lookupNamespaceURI(a.parentNode,b);break a;case 2:c=this.lookupNamespaceURI(a.ownerElement,b);break a;case 9:c=this.lookupNamespaceURI(a.documentElement,b);break a;case 6:case 12:case 10:case 11:break a;default:c=this.lookupNamespaceURI(a.parentNode,
b)}return c},getXMLDoc:function(){OpenLayers.Format.XML.document||this.xmldom||(document.implementation&&document.implementation.createDocument?OpenLayers.Format.XML.document=document.implementation.createDocument("","",null):!this.xmldom&&window.ActiveXObject&&(this.xmldom=new ActiveXObject("Microsoft.XMLDOM")));return OpenLayers.Format.XML.document||this.xmldom},CLASS_NAME:"OpenLayers.Format.XML"});OpenLayers.Format.XML.CONTENT_TYPE={EMPTY:0,SIMPLE:1,COMPLEX:2,MIXED:3};
OpenLayers.Format.XML.lookupNamespaceURI=OpenLayers.Function.bind(OpenLayers.Format.XML.prototype.lookupNamespaceURI,OpenLayers.Format.XML.prototype);OpenLayers.Format.XML.document=null;OpenLayers.Format.WFST=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.WFST.DEFAULTS);var b=OpenLayers.Format.WFST["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported WFST version: "+a.version;return new b(a)};OpenLayers.Format.WFST.DEFAULTS={version:"1.0.0"};OpenLayers.Feature=OpenLayers.Class({layer:null,id:null,lonlat:null,data:null,marker:null,popupClass:null,popup:null,initialize:function(a,b,c){this.layer=a;this.lonlat=b;this.data=null!=c?c:{};this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){null!=this.layer&&null!=this.layer.map&&null!=this.popup&&this.layer.map.removePopup(this.popup);null!=this.layer&&null!=this.marker&&this.layer.removeMarker(this.marker);this.data=this.lonlat=this.id=this.layer=null;null!=this.marker&&
(this.destroyMarker(this.marker),this.marker=null);null!=this.popup&&(this.destroyPopup(this.popup),this.popup=null)},onScreen:function(){var a=!1;null!=this.layer&&null!=this.layer.map&&(a=this.layer.map.getExtent().containsLonLat(this.lonlat));return a},createMarker:function(){null!=this.lonlat&&(this.marker=new OpenLayers.Marker(this.lonlat,this.data.icon));return this.marker},destroyMarker:function(){this.marker.destroy()},createPopup:function(a){null!=this.lonlat&&(this.popup||(this.popup=new (this.popupClass?
this.popupClass:OpenLayers.Popup.Anchored)(this.id+"_popup",this.lonlat,this.data.popupSize,this.data.popupContentHTML,this.marker?this.marker.icon:null,a)),null!=this.data.overflow&&(this.popup.contentDiv.style.overflow=this.data.overflow),this.popup.feature=this);return this.popup},destroyPopup:function(){this.popup&&(this.popup.feature=null,this.popup.destroy(),this.popup=null)},CLASS_NAME:"OpenLayers.Feature"});OpenLayers.State={UNKNOWN:"Unknown",INSERT:"Insert",UPDATE:"Update",DELETE:"Delete"};
OpenLayers.Feature.Vector=OpenLayers.Class(OpenLayers.Feature,{fid:null,geometry:null,attributes:null,bounds:null,state:null,style:null,url:null,renderIntent:"default",modified:null,initialize:function(a,b,c){OpenLayers.Feature.prototype.initialize.apply(this,[null,null,b]);this.lonlat=null;this.geometry=a?a:null;this.state=null;this.attributes={};b&&(this.attributes=OpenLayers.Util.extend(this.attributes,b));this.style=c?c:null},destroy:function(){this.layer&&(this.layer.removeFeatures(this),this.layer=
null);this.modified=this.geometry=null;OpenLayers.Feature.prototype.destroy.apply(this,arguments)},clone:function(){return new OpenLayers.Feature.Vector(this.geometry?this.geometry.clone():null,this.attributes,this.style)},onScreen:function(a){var b=!1;this.layer&&this.layer.map&&(b=this.layer.map.getExtent(),a?(a=this.geometry.getBounds(),b=b.intersectsBounds(a)):b=b.toGeometry().intersects(this.geometry));return b},getVisibility:function(){return!(this.style&&"none"==this.style.display||!this.layer||
this.layer&&this.layer.styleMap&&"none"==this.layer.styleMap.createSymbolizer(this,this.renderIntent).display||this.layer&&!this.layer.getVisibility())},createMarker:function(){return null},destroyMarker:function(){},createPopup:function(){return null},atPoint:function(a,b,c){var d=!1;this.geometry&&(d=this.geometry.atPoint(a,b,c));return d},destroyPopup:function(){},move:function(a){if(this.layer&&this.geometry.move){a="OpenLayers.LonLat"==a.CLASS_NAME?this.layer.getViewPortPxFromLonLat(a):a;var b=
this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat()),c=this.layer.map.getResolution();this.geometry.move(c*(a.x-b.x),c*(b.y-a.y));this.layer.drawFeature(this);return b}},toState:function(a){if(a==OpenLayers.State.UPDATE)switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.DELETE:this.state=a}else if(a==OpenLayers.State.INSERT)switch(this.state){case OpenLayers.State.UNKNOWN:break;default:this.state=a}else if(a==OpenLayers.State.DELETE)switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.UPDATE:this.state=
a}else a==OpenLayers.State.UNKNOWN&&(this.state=a)},CLASS_NAME:"OpenLayers.Feature.Vector"});
OpenLayers.Feature.Vector.style={"default":{fillColor:"#ee9900",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#ee9900",strokeOpacity:1,strokeWidth:1,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},select:{fillColor:"blue",fillOpacity:0.4,
hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"blue",strokeOpacity:1,strokeWidth:2,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"pointer",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},temporary:{fillColor:"#66cccc",fillOpacity:0.2,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#66cccc",strokeOpacity:1,
strokeLinecap:"round",strokeWidth:2,strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},"delete":{display:"none"}};OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:!1,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:!1,propertyStyles:null,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.rules=[];b&&b.rules&&this.addRules(b.rules);this.setDefaultStyle(a||OpenLayers.Feature.Vector.style["default"]);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a=0,b=this.rules.length;a<b;a++)this.rules[a].destroy(),
this.rules[a]=null;this.defaultStyle=this.rules=null},createSymbolizer:function(a){for(var b=this.defaultsPerSymbolizer?{}:this.createLiterals(OpenLayers.Util.extend({},this.defaultStyle),a),c=this.rules,d,e=[],f=!1,g=0,h=c.length;g<h;g++)d=c[g],d.evaluate(a)&&(d instanceof OpenLayers.Rule&&d.elseFilter?e.push(d):(f=!0,this.applySymbolizer(d,b,a)));if(!1==f&&0<e.length)for(f=!0,g=0,h=e.length;g<h;g++)this.applySymbolizer(e[g],b,a);0<c.length&&!1==f&&(b.display="none");null!=b.label&&"string"!==typeof b.label&&
(b.label=String(b.label));return b},applySymbolizer:function(a,b,c){var d=c.geometry?this.getSymbolizerPrefix(c.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0];a=a.symbolizer[d]||a.symbolizer;!0===this.defaultsPerSymbolizer&&(d=this.defaultStyle,OpenLayers.Util.applyDefaults(a,{pointRadius:d.pointRadius}),!0!==a.stroke&&!0!==a.graphic||OpenLayers.Util.applyDefaults(a,{strokeWidth:d.strokeWidth,strokeColor:d.strokeColor,strokeOpacity:d.strokeOpacity,strokeDashstyle:d.strokeDashstyle,strokeLinecap:d.strokeLinecap}),
!0!==a.fill&&!0!==a.graphic||OpenLayers.Util.applyDefaults(a,{fillColor:d.fillColor,fillOpacity:d.fillOpacity}),!0===a.graphic&&OpenLayers.Util.applyDefaults(a,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset,graphicYOffset:this.defaultStyle.graphicYOffset}));
return this.createLiterals(OpenLayers.Util.extend(b,a),c)},createLiterals:function(a,b){var c=OpenLayers.Util.extend({},b.attributes||b.data);OpenLayers.Util.extend(c,this.context);for(var d in this.propertyStyles)a[d]=OpenLayers.Style.createLiteral(a[d],c,b,d);return a},findPropertyStyles:function(){var a={};this.addPropertyStyles(a,this.defaultStyle);for(var b=this.rules,c,d,e=0,f=b.length;e<f;e++){c=b[e].symbolizer;for(var g in c)if(d=c[g],"object"==typeof d)this.addPropertyStyles(a,d);else{this.addPropertyStyles(a,
c);break}}return a},addPropertyStyles:function(a,b){var c,d;for(d in b)c=b[d],"string"==typeof c&&c.match(/\$\{\w+\}/)&&(a[d]=!0);return a},addRules:function(a){Array.prototype.push.apply(this.rules,a);this.propertyStyles=this.findPropertyStyles()},setDefaultStyle:function(a){this.defaultStyle=a;this.propertyStyles=this.findPropertyStyles()},getSymbolizerPrefix:function(a){for(var b=OpenLayers.Style.SYMBOLIZER_PREFIXES,c=0,d=b.length;c<d;c++)if(-1!=a.CLASS_NAME.indexOf(b[c]))return b[c]},clone:function(){var a=
OpenLayers.Util.extend({},this);if(this.rules){a.rules=[];for(var b=0,c=this.rules.length;b<c;++b)a.rules.push(this.rules[b].clone())}a.context=this.context&&OpenLayers.Util.extend({},this.context);b=OpenLayers.Util.extend({},this.defaultStyle);return new OpenLayers.Style(b,a)},CLASS_NAME:"OpenLayers.Style"});OpenLayers.Style.createLiteral=function(a,b,c,d){"string"==typeof a&&-1!=a.indexOf("${")&&(a=OpenLayers.String.format(a,b,[c,d]),a=isNaN(a)||!a?a:parseFloat(a));return a};
OpenLayers.Style.SYMBOLIZER_PREFIXES=["Point","Line","Polygon","Text","Raster"];OpenLayers.Filter=OpenLayers.Class({initialize:function(a){OpenLayers.Util.extend(this,a)},destroy:function(){},evaluate:function(a){return!0},clone:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.CQL?OpenLayers.Format.CQL.prototype.write(this):Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Filter"});OpenLayers.Filter.Spatial=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,distance:null,distanceUnits:null,evaluate:function(a){var b=!1;switch(this.type){case OpenLayers.Filter.Spatial.BBOX:case OpenLayers.Filter.Spatial.INTERSECTS:if(a.geometry){var c=this.value;"OpenLayers.Bounds"==this.value.CLASS_NAME&&(c=this.value.toGeometry());a.geometry.intersects(c)&&(b=!0)}break;default:throw Error("evaluate is not implemented for this filter type.");}return b},clone:function(){var a=
OpenLayers.Util.applyDefaults({value:this.value&&this.value.clone&&this.value.clone()},this);return new OpenLayers.Filter.Spatial(a)},CLASS_NAME:"OpenLayers.Filter.Spatial"});OpenLayers.Filter.Spatial.BBOX="BBOX";OpenLayers.Filter.Spatial.INTERSECTS="INTERSECTS";OpenLayers.Filter.Spatial.DWITHIN="DWITHIN";OpenLayers.Filter.Spatial.WITHIN="WITHIN";OpenLayers.Filter.Spatial.CONTAINS="CONTAINS";OpenLayers.Filter.FeatureId=OpenLayers.Class(OpenLayers.Filter,{fids:null,type:"FID",initialize:function(a){this.fids=[];OpenLayers.Filter.prototype.initialize.apply(this,[a])},evaluate:function(a){for(var b=0,c=this.fids.length;b<c;b++)if((a.fid||a.id)==this.fids[b])return!0;return!1},clone:function(){var a=new OpenLayers.Filter.FeatureId;OpenLayers.Util.extend(a,this);a.fids=this.fids.slice();return a},CLASS_NAME:"OpenLayers.Filter.FeatureId"});OpenLayers.Format.WFST.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs",gml:"http://www.opengis.net/gml",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows"},defaultPrefix:"wfs",version:null,schemaLocations:null,srsName:null,extractAttributes:!0,xy:!0,stateName:null,initialize:function(a){this.stateName={};this.stateName[OpenLayers.State.INSERT]="wfs:Insert";this.stateName[OpenLayers.State.UPDATE]=
"wfs:Update";this.stateName[OpenLayers.State.DELETE]="wfs:Delete";OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},getSrsName:function(a,b){var c=b&&b.srsName;c||(c=a&&a.layer?a.layer.projection.getCode():this.srsName);return c},read:function(a,b){b=b||{};OpenLayers.Util.applyDefaults(b,{output:"features"});"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var c={};a&&this.readNode(a,c,!0);c.features&&"features"===b.output&&
(c=c.features);return c},readers:{wfs:{FeatureCollection:function(a,b){b.features=[];this.readChildNodes(a,b)}}},write:function(a,b){var c=this.writeNode("wfs:Transaction",{features:a,options:b}),d=this.schemaLocationAttr();d&&this.setAttributeNS(c,this.namespaces.xsi,"xsi:schemaLocation",d);return OpenLayers.Format.XML.prototype.write.apply(this,[c])},writers:{wfs:{GetFeature:function(a){var b=this.createElementNSPlus("wfs:GetFeature",{attributes:{service:"WFS",version:this.version,handle:a&&a.handle,
outputFormat:a&&a.outputFormat,maxFeatures:a&&a.maxFeatures,"xsi:schemaLocation":this.schemaLocationAttr(a)}});if("string"==typeof this.featureType)this.writeNode("Query",a,b);else for(var c=0,d=this.featureType.length;c<d;c++)a.featureType=this.featureType[c],this.writeNode("Query",a,b);return b},Transaction:function(a){a=a||{};var b=a.options||{},c=this.createElementNSPlus("wfs:Transaction",{attributes:{service:"WFS",version:this.version,handle:b.handle}}),d,e=a.features;if(e){!0===b.multi&&OpenLayers.Util.extend(this.geometryTypes,
{"OpenLayers.Geometry.Point":"MultiPoint","OpenLayers.Geometry.LineString":!0===this.multiCurve?"MultiCurve":"MultiLineString","OpenLayers.Geometry.Polygon":!0===this.multiSurface?"MultiSurface":"MultiPolygon"});var f,g;a=0;for(d=e.length;a<d;++a)g=e[a],(f=this.stateName[g.state])&&this.writeNode(f,{feature:g,options:b},c);!0===b.multi&&this.setGeometryTypes()}if(b.nativeElements)for(a=0,d=b.nativeElements.length;a<d;++a)this.writeNode("wfs:Native",b.nativeElements[a],c);return c},Native:function(a){return this.createElementNSPlus("wfs:Native",
{attributes:{vendorId:a.vendorId,safeToIgnore:a.safeToIgnore},value:a.value})},Insert:function(a){var b=a.feature;a=a.options;a=this.createElementNSPlus("wfs:Insert",{attributes:{handle:a&&a.handle}});this.srsName=this.getSrsName(b);this.writeNode("feature:_typeName",b,a);return a},Update:function(a){var b=a.feature;a=a.options;a=this.createElementNSPlus("wfs:Update",{attributes:{handle:a&&a.handle,typeName:(this.featureNS?this.featurePrefix+":":"")+this.featureType}});this.featureNS&&a.setAttribute("xmlns:"+
this.featurePrefix,this.featureNS);var c=b.modified;null===this.geometryName||c&&void 0===c.geometry||(this.srsName=this.getSrsName(b),this.writeNode("Property",{name:this.geometryName,value:b.geometry},a));for(var d in b.attributes)void 0===b.attributes[d]||c&&c.attributes&&(!c.attributes||void 0===c.attributes[d])||this.writeNode("Property",{name:d,value:b.attributes[d]},a);this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[b.fid]}),a);return a},Property:function(a){var b=this.createElementNSPlus("wfs:Property");
this.writeNode("Name",a.name,b);null!==a.value&&this.writeNode("Value",a.value,b);return b},Name:function(a){return this.createElementNSPlus("wfs:Name",{value:a})},Value:function(a){var b;a instanceof OpenLayers.Geometry?(b=this.createElementNSPlus("wfs:Value"),a=this.writeNode("feature:_geometry",a).firstChild,b.appendChild(a)):b=this.createElementNSPlus("wfs:Value",{value:a});return b},Delete:function(a){var b=a.feature;a=a.options;a=this.createElementNSPlus("wfs:Delete",{attributes:{handle:a&&
a.handle,typeName:(this.featureNS?this.featurePrefix+":":"")+this.featureType}});this.featureNS&&a.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[b.fid]}),a);return a}}},schemaLocationAttr:function(a){a=OpenLayers.Util.extend({featurePrefix:this.featurePrefix,schema:this.schema},a);var b=OpenLayers.Util.extend({},this.schemaLocations);a.schema&&(b[a.featurePrefix]=a.schema);a=[];var c,d;for(d in b)(c=this.namespaces[d])&&
a.push(c+" "+b[d]);return a.join(" ")||void 0},setFilterProperty:function(a){if(a.filters)for(var b=0,c=a.filters.length;b<c;++b)OpenLayers.Format.WFST.v1.prototype.setFilterProperty.call(this,a.filters[b]);else a instanceof OpenLayers.Filter.Spatial&&!a.property&&(a.property=this.geometryName)},CLASS_NAME:"OpenLayers.Format.WFST.v1"});OpenLayers.Format.OGCExceptionReport=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},defaultPrefix:"ogc",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b={exceptionReport:null};a.documentElement&&(this.readChildNodes(a,b),null===b.exceptionReport&&(b=(new OpenLayers.Format.OWSCommon).read(a)));return b},readers:{ogc:{ServiceExceptionReport:function(a,
b){b.exceptionReport={exceptions:[]};this.readChildNodes(a,b.exceptionReport)},ServiceException:function(a,b){var c={code:a.getAttribute("code"),locator:a.getAttribute("locator"),text:this.getChildValue(a)};b.exceptions.push(c)}}},CLASS_NAME:"OpenLayers.Format.OGCExceptionReport"});OpenLayers.Format.XML.VersionedOGC=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:null,version:null,profile:null,allowFallback:!1,name:null,stringifyOutput:!1,parser:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);a=this.CLASS_NAME;this.name=a.substring(a.lastIndexOf(".")+1)},getVersion:function(a,b){var c;a?(c=this.version,c||(c=a.getAttribute("version"),c||(c=this.defaultVersion))):c=b&&b.version||this.version||this.defaultVersion;return c},getParser:function(a){a=
a||this.defaultVersion;var b=this.profile?"_"+this.profile:"";if(!this.parser||this.parser.VERSION!=a){var c=OpenLayers.Format[this.name]["v"+a.replace(/\./g,"_")+b];if(!c&&(""!==b&&this.allowFallback&&(b="",c=OpenLayers.Format[this.name]["v"+a.replace(/\./g,"_")]),!c))throw"Can't find a "+this.name+" parser for version "+a+b;this.parser=new c(this.options)}return this.parser},write:function(a,b){var c=this.getVersion(null,b);this.parser=this.getParser(c);c=this.parser.write(a,b);return!1===this.stringifyOutput?
c:OpenLayers.Format.XML.prototype.write.apply(this,[c])},read:function(a,b){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var c=this.getVersion(a.documentElement);this.parser=this.getParser(c);var d=this.parser.read(a,b),e=this.parser.errorProperty||null;null!==e&&void 0===d[e]&&(e=new OpenLayers.Format.OGCExceptionReport,d.error=e.read(a));d.version=c;return d},CLASS_NAME:"OpenLayers.Format.XML.VersionedOGC"});OpenLayers.Filter.Logical=OpenLayers.Class(OpenLayers.Filter,{filters:null,type:null,initialize:function(a){this.filters=[];OpenLayers.Filter.prototype.initialize.apply(this,[a])},destroy:function(){this.filters=null;OpenLayers.Filter.prototype.destroy.apply(this)},evaluate:function(a){var b,c;switch(this.type){case OpenLayers.Filter.Logical.AND:b=0;for(c=this.filters.length;b<c;b++)if(!1==this.filters[b].evaluate(a))return!1;return!0;case OpenLayers.Filter.Logical.OR:b=0;for(c=this.filters.length;b<
c;b++)if(!0==this.filters[b].evaluate(a))return!0;return!1;case OpenLayers.Filter.Logical.NOT:return!this.filters[0].evaluate(a)}},clone:function(){for(var a=[],b=0,c=this.filters.length;b<c;++b)a.push(this.filters[b].clone());return new OpenLayers.Filter.Logical({type:this.type,filters:a})},CLASS_NAME:"OpenLayers.Filter.Logical"});OpenLayers.Filter.Logical.AND="&&";OpenLayers.Filter.Logical.OR="||";OpenLayers.Filter.Logical.NOT="!";OpenLayers.Filter.Comparison=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,matchCase:!0,lowerBoundary:null,upperBoundary:null,initialize:function(a){OpenLayers.Filter.prototype.initialize.apply(this,[a]);this.type===OpenLayers.Filter.Comparison.LIKE&&void 0===a.matchCase&&(this.matchCase=null)},evaluate:function(a){a instanceof OpenLayers.Feature.Vector&&(a=a.attributes);var b=!1;a=a[this.property];switch(this.type){case OpenLayers.Filter.Comparison.EQUAL_TO:b=this.value;
b=this.matchCase||"string"!=typeof a||"string"!=typeof b?a==b:a.toUpperCase()==b.toUpperCase();break;case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:b=this.value;b=this.matchCase||"string"!=typeof a||"string"!=typeof b?a!=b:a.toUpperCase()!=b.toUpperCase();break;case OpenLayers.Filter.Comparison.LESS_THAN:b=a<this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN:b=a>this.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:b=a<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:b=
a>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:b=a>=this.lowerBoundary&&a<=this.upperBoundary;break;case OpenLayers.Filter.Comparison.LIKE:b=RegExp(this.value,"gi").test(a);break;case OpenLayers.Filter.Comparison.IS_NULL:b=null===a}return b},value2regex:function(a,b,c){if("."==a)throw Error("'.' is an unsupported wildCard character for OpenLayers.Filter.Comparison");a=a?a:"*";b=b?b:".";this.value=this.value.replace(RegExp("\\"+(c?c:"!")+"(.|$)","g"),"\\$1");this.value=this.value.replace(RegExp("\\"+
b,"g"),".");this.value=this.value.replace(RegExp("\\"+a,"g"),".*");this.value=this.value.replace(RegExp("\\\\.\\*","g"),"\\"+a);return this.value=this.value.replace(RegExp("\\\\\\.","g"),"\\"+b)},regex2value:function(){var a=this.value,a=a.replace(/!/g,"!!"),a=a.replace(/(\\)?\\\./g,function(a,c){return c?a:"!."}),a=a.replace(/(\\)?\\\*/g,function(a,c){return c?a:"!*"}),a=a.replace(/\\\\/g,"\\");return a=a.replace(/\.\*/g,"*")},clone:function(){return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison,
this)},CLASS_NAME:"OpenLayers.Filter.Comparison"});OpenLayers.Filter.Comparison.EQUAL_TO="==";OpenLayers.Filter.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Filter.Comparison.LESS_THAN="<";OpenLayers.Filter.Comparison.GREATER_THAN=">";OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Filter.Comparison.BETWEEN="..";OpenLayers.Filter.Comparison.LIKE="~";OpenLayers.Filter.Comparison.IS_NULL="NULL";OpenLayers.Format.Filter=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.Filter"});OpenLayers.Filter.Function=OpenLayers.Class(OpenLayers.Filter,{name:null,params:null,CLASS_NAME:"OpenLayers.Filter.Function"});OpenLayers.Date={dateRegEx:/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/,toISOString:function(){return"toISOString"in Date.prototype?function(a){return a.toISOString()}:function(a){return isNaN(a.getTime())?"Invalid Date":a.getUTCFullYear()+"-"+OpenLayers.Number.zeroPad(a.getUTCMonth()+1,2)+"-"+OpenLayers.Number.zeroPad(a.getUTCDate(),2)+"T"+OpenLayers.Number.zeroPad(a.getUTCHours(),2)+":"+OpenLayers.Number.zeroPad(a.getUTCMinutes(),
2)+":"+OpenLayers.Number.zeroPad(a.getUTCSeconds(),2)+"."+OpenLayers.Number.zeroPad(a.getUTCMilliseconds(),3)+"Z"}}(),parse:function(a){var b;if((a=a.match(this.dateRegEx))&&(a[1]||a[7])){b=parseInt(a[1],10)||0;var c=parseInt(a[2],10)-1||0,d=parseInt(a[3],10)||1;b=new Date(Date.UTC(b,c,d));if(c=a[7]){var d=parseInt(a[4],10),e=parseInt(a[5],10),f=parseFloat(a[6]),g=f|0,f=Math.round(1E3*(f-g));b.setUTCHours(d,e,g,f);"Z"!==c&&(c=parseInt(c,10),a=parseInt(a[8],10)||0,a=-1E3*(60*60*c+60*a),b=new Date(b.getTime()+
a))}}else b=new Date("invalid");return b}};OpenLayers.Format.Filter.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"ogc",schemaLocation:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){var b={};this.readers.ogc.Filter.apply(this,[a,b]);return b.filter},readers:{ogc:{_expression:function(a){for(var b="",c=a.firstChild;c;c=
c.nextSibling)switch(c.nodeType){case 1:a=this.readNode(c);a.property?b+="${"+a.property+"}":void 0!==a.value&&(b+=a.value);break;case 3:case 4:b+=c.nodeValue}return b},Filter:function(a,b){var c={fids:[],filters:[]};this.readChildNodes(a,c);0<c.fids.length?b.filter=new OpenLayers.Filter.FeatureId({fids:c.fids}):0<c.filters.length&&(b.filter=c.filters[0])},FeatureId:function(a,b){var c=a.getAttribute("fid");c&&b.fids.push(c)},And:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND});
this.readChildNodes(a,c);b.filters.push(c)},Or:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.OR});this.readChildNodes(a,c);b.filters.push(c)},Not:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.NOT});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThan:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThan:function(a,
b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},
PropertyIsBetween:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.BETWEEN});this.readChildNodes(a,c);b.filters.push(c)},Literal:function(a,b){b.value=OpenLayers.String.numericIf(this.getChildValue(a),!0)},PropertyName:function(a,b){b.property=this.getChildValue(a)},LowerBoundary:function(a,b){b.lowerBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,a),!0)},UpperBoundary:function(a,b){b.upperBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,
a),!0)},Intersects:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.INTERSECTS)},Within:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.WITHIN)},Contains:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.CONTAINS)},DWithin:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.DWITHIN)},Distance:function(a,b){b.distance=parseInt(this.getChildValue(a));b.distanceUnits=a.getAttribute("units")},Function:function(a,b){},PropertyIsNull:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.IS_NULL});
this.readChildNodes(a,c);b.filters.push(c)}}},readSpatial:function(a,b,c){c=new OpenLayers.Filter.Spatial({type:c});this.readChildNodes(a,c);c.value=c.components[0];delete c.components;b.filters.push(c)},encodeLiteral:function(a){a instanceof Date&&(a=OpenLayers.Date.toISOString(a));return a},writeOgcExpression:function(a,b){a instanceof OpenLayers.Filter.Function?this.writeNode("Function",a,b):this.writeNode("Literal",a,b);return b},write:function(a){return this.writers.ogc.Filter.apply(this,[a])},
writers:{ogc:{Filter:function(a){var b=this.createElementNSPlus("ogc:Filter");this.writeNode(this.getFilterType(a),a,b);return b},_featureIds:function(a){for(var b=this.createDocumentFragment(),c=0,d=a.fids.length;c<d;++c)this.writeNode("ogc:FeatureId",a.fids[c],b);return b},FeatureId:function(a){return this.createElementNSPlus("ogc:FeatureId",{attributes:{fid:a}})},And:function(a){for(var b=this.createElementNSPlus("ogc:And"),c,d=0,e=a.filters.length;d<e;++d)c=a.filters[d],this.writeNode(this.getFilterType(c),
c,b);return b},Or:function(a){for(var b=this.createElementNSPlus("ogc:Or"),c,d=0,e=a.filters.length;d<e;++d)c=a.filters[d],this.writeNode(this.getFilterType(c),c,b);return b},Not:function(a){var b=this.createElementNSPlus("ogc:Not");a=a.filters[0];this.writeNode(this.getFilterType(a),a,b);return b},PropertyIsLessThan:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLessThan");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsGreaterThan:function(a){var b=
this.createElementNSPlus("ogc:PropertyIsGreaterThan");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLessThanOrEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsGreaterThanOrEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);
return b},PropertyIsBetween:function(a){var b=this.createElementNSPlus("ogc:PropertyIsBetween");this.writeNode("PropertyName",a,b);this.writeNode("LowerBoundary",a,b);this.writeNode("UpperBoundary",a,b);return b},PropertyName:function(a){return this.createElementNSPlus("ogc:PropertyName",{value:a.property})},Literal:function(a){return this.createElementNSPlus("ogc:Literal",{value:(this.encodeLiteral||OpenLayers.Format.Filter.v1.prototype.encodeLiteral)(a)})},LowerBoundary:function(a){var b=this.createElementNSPlus("ogc:LowerBoundary");
this.writeOgcExpression(a.lowerBoundary,b);return b},UpperBoundary:function(a){var b=this.createElementNSPlus("ogc:UpperBoundary");this.writeNode("Literal",a.upperBoundary,b);return b},INTERSECTS:function(a){return this.writeSpatial(a,"Intersects")},WITHIN:function(a){return this.writeSpatial(a,"Within")},CONTAINS:function(a){return this.writeSpatial(a,"Contains")},DWITHIN:function(a){var b=this.writeSpatial(a,"DWithin");this.writeNode("Distance",a,b);return b},Distance:function(a){return this.createElementNSPlus("ogc:Distance",
{attributes:{units:a.distanceUnits},value:a.distance})},Function:function(a){var b=this.createElementNSPlus("ogc:Function",{attributes:{name:a.name}});a=a.params;for(var c=0,d=a.length;c<d;c++)this.writeOgcExpression(a[c],b);return b},PropertyIsNull:function(a){var b=this.createElementNSPlus("ogc:PropertyIsNull");this.writeNode("PropertyName",a,b);return b}}},getFilterType:function(a){var b=this.filterMap[a.type];if(!b)throw"Filter writing not supported for rule type: "+a.type;return b},filterMap:{"&&":"And",
"||":"Or","!":"Not","==":"PropertyIsEqualTo","!=":"PropertyIsNotEqualTo","<":"PropertyIsLessThan",">":"PropertyIsGreaterThan","<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike",NULL:"PropertyIsNull",BBOX:"BBOX",DWITHIN:"DWITHIN",WITHIN:"WITHIN",CONTAINS:"CONTAINS",INTERSECTS:"INTERSECTS",FID:"_featureIds"},CLASS_NAME:"OpenLayers.Format.Filter.v1"});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){this.bounds=this.id=null},clone:function(){return new OpenLayers.Geometry},setBounds:function(a){a&&(this.bounds=a.clone())},clearBounds:function(){this.bounds=null;this.parent&&this.parent.clearBounds()},extendBounds:function(a){this.getBounds()?this.bounds.extend(a):this.setBounds(a)},getBounds:function(){null==this.bounds&&this.calculateBounds();
return this.bounds},calculateBounds:function(){},distanceTo:function(a,b){},getVertices:function(a){},atPoint:function(a,b,c){var d=!1;null!=this.getBounds()&&null!=a&&(b=null!=b?b:0,c=null!=c?c:0,d=(new OpenLayers.Bounds(this.bounds.left-b,this.bounds.bottom-c,this.bounds.right+b,this.bounds.top+c)).containsLonLat(a));return d},getLength:function(){return 0},getArea:function(){return 0},getCentroid:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.WKT?OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this)):
Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(a){var b;if(OpenLayers.Format&&OpenLayers.Format.WKT){var c=OpenLayers.Geometry.fromWKT.format;c||(c=new OpenLayers.Format.WKT,OpenLayers.Geometry.fromWKT.format=c);a=c.read(a);if(a instanceof OpenLayers.Feature.Vector)b=a.geometry;else if(OpenLayers.Util.isArray(a)){b=a.length;for(var c=Array(b),d=0;d<b;++d)c[d]=a[d].geometry;b=new OpenLayers.Geometry.Collection(c)}}return b};
OpenLayers.Geometry.segmentsIntersect=function(a,b,c){var d=c&&c.point;c=c&&c.tolerance;var e=!1,f=a.x1-b.x1,g=a.y1-b.y1,h=a.x2-a.x1,k=a.y2-a.y1,l=b.y2-b.y1,m=b.x2-b.x1,n=l*h-m*k,l=m*g-l*f,g=h*g-k*f;0==n?0==l&&0==g&&(e=!0):(f=l/n,n=g/n,0<=f&&(1>=f&&0<=n&&1>=n)&&(d?(h=a.x1+f*h,n=a.y1+f*k,e=new OpenLayers.Geometry.Point(h,n)):e=!0));if(c)if(e){if(d)a:for(a=[a,b],b=0;2>b;++b)for(f=a[b],k=1;3>k;++k)if(h=f["x"+k],n=f["y"+k],d=Math.sqrt(Math.pow(h-e.x,2)+Math.pow(n-e.y,2)),d<c){e.x=h;e.y=n;break a}}else a:for(a=
[a,b],b=0;2>b;++b)for(h=a[b],n=a[(b+1)%2],k=1;3>k;++k)if(f={x:h["x"+k],y:h["y"+k]},g=OpenLayers.Geometry.distanceToSegment(f,n),g.distance<c){e=d?new OpenLayers.Geometry.Point(f.x,f.y):!0;break a}return e};OpenLayers.Geometry.distanceToSegment=function(a,b){var c=OpenLayers.Geometry.distanceSquaredToSegment(a,b);c.distance=Math.sqrt(c.distance);return c};
OpenLayers.Geometry.distanceSquaredToSegment=function(a,b){var c=a.x,d=a.y,e=b.x1,f=b.y1,g=b.x2,h=b.y2,k=g-e,l=h-f,m=(k*(c-e)+l*(d-f))/(Math.pow(k,2)+Math.pow(l,2));0>=m||(1<=m?(e=g,f=h):(e+=m*k,f+=m*l));return{distance:Math.pow(e-c,2)+Math.pow(f-d,2),x:e,y:f,along:m}};OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(a,b){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(a);this.y=parseFloat(b)},clone:function(a){null==a&&(a=new OpenLayers.Geometry.Point(this.x,this.y));OpenLayers.Util.applyDefaults(a,this);return a},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y)},distanceTo:function(a,b){var c=!(b&&!1===b.edge)&&b&&b.details,d,e,f,g,h;a instanceof
OpenLayers.Geometry.Point?(e=this.x,f=this.y,g=a.x,h=a.y,d=Math.sqrt(Math.pow(e-g,2)+Math.pow(f-h,2)),d=c?{x0:e,y0:f,x1:g,y1:h,distance:d}:d):(d=a.distanceTo(this,b),c&&(d={x0:d.x1,y0:d.y1,x1:d.x0,y1:d.y0,distance:d.distance}));return d},equals:function(a){var b=!1;null!=a&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},toShortString:function(){return this.x+", "+this.y},move:function(a,b){this.x+=a;this.y+=b;this.clearBounds()},rotate:function(a,b){a*=
Math.PI/180;var c=this.distanceTo(b),d=a+Math.atan2(this.y-b.y,this.x-b.x);this.x=b.x+c*Math.cos(d);this.y=b.y+c*Math.sin(d);this.clearBounds()},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y)},resize:function(a,b,c){this.x=b.x+a*(void 0==c?1:c)*(this.x-b.x);this.y=b.y+a*(this.y-b.y);this.clearBounds();return this},intersects:function(a){var b=!1;return b="OpenLayers.Geometry.Point"==a.CLASS_NAME?this.equals(a):a.intersects(this)},transform:function(a,b){a&&b&&(OpenLayers.Projection.transform(this,
a,b),this.bounds=null);return this},getVertices:function(a){return[this]},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(a){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];null!=a&&this.addComponents(a)},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments)},clone:function(){for(var a=eval("new "+this.CLASS_NAME+"()"),b=0,c=this.components.length;b<c;b++)a.addComponent(this.components[b].clone());
OpenLayers.Util.applyDefaults(a,this);return a},getComponentsString:function(){for(var a=[],b=0,c=this.components.length;b<c;b++)a.push(this.components[b].toShortString());return a.join(",")},calculateBounds:function(){this.bounds=null;var a=new OpenLayers.Bounds,b=this.components;if(b)for(var c=0,d=b.length;c<d;c++)a.extend(b[c].getBounds());null!=a.left&&(null!=a.bottom&&null!=a.right&&null!=a.top)&&this.setBounds(a)},addComponents:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0,c=a.length;b<
c;b++)this.addComponent(a[b])},addComponent:function(a,b){var c=!1;if(a&&(null==this.componentTypes||-1<OpenLayers.Util.indexOf(this.componentTypes,a.CLASS_NAME))){if(null!=b&&b<this.components.length){var c=this.components.slice(0,b),d=this.components.slice(b,this.components.length);c.push(a);this.components=c.concat(d)}else this.components.push(a);a.parent=this;this.clearBounds();c=!0}return c},removeComponents:function(a){var b=!1;OpenLayers.Util.isArray(a)||(a=[a]);for(var c=a.length-1;0<=c;--c)b=
this.removeComponent(a[c])||b;return b},removeComponent:function(a){OpenLayers.Util.removeItem(this.components,a);this.clearBounds();return!0},getLength:function(){for(var a=0,b=0,c=this.components.length;b<c;b++)a+=this.components[b].getLength();return a},getArea:function(){for(var a=0,b=0,c=this.components.length;b<c;b++)a+=this.components[b].getArea();return a},getGeodesicArea:function(a){for(var b=0,c=0,d=this.components.length;c<d;c++)b+=this.components[c].getGeodesicArea(a);return b},getCentroid:function(a){if(!a)return this.components.length&&
this.components[0].getCentroid();a=this.components.length;if(!a)return!1;for(var b=[],c=[],d=0,e=Number.MAX_VALUE,f,g=0;g<a;++g){f=this.components[g];var h=f.getArea();f=f.getCentroid(!0);isNaN(h)||(isNaN(f.x)||isNaN(f.y))||(b.push(h),d+=h,e=h<e&&0<h?h:e,c.push(f))}a=b.length;if(0===d){for(g=0;g<a;++g)b[g]=1;d=b.length}else{for(g=0;g<a;++g)b[g]/=e;d/=e}for(var k=e=0,g=0;g<a;++g)f=c[g],h=b[g],e+=f.x*h,k+=f.y*h;return new OpenLayers.Geometry.Point(e/d,k/d)},getGeodesicLength:function(a){for(var b=0,
c=0,d=this.components.length;c<d;c++)b+=this.components[c].getGeodesicLength(a);return b},move:function(a,b){for(var c=0,d=this.components.length;c<d;c++)this.components[c].move(a,b)},rotate:function(a,b){for(var c=0,d=this.components.length;c<d;++c)this.components[c].rotate(a,b)},resize:function(a,b,c){for(var d=0;d<this.components.length;++d)this.components[d].resize(a,b,c);return this},distanceTo:function(a,b){for(var c=!(b&&!1===b.edge)&&b&&b.details,d,e,f,g=Number.POSITIVE_INFINITY,h=0,k=this.components.length;h<
k&&!(d=this.components[h].distanceTo(a,b),f=c?d.distance:d,f<g&&(g=f,e=d,0==g));++h);return e},equals:function(a){var b=!0;if(a&&a.CLASS_NAME&&this.CLASS_NAME==a.CLASS_NAME)if(OpenLayers.Util.isArray(a.components)&&a.components.length==this.components.length)for(var c=0,d=this.components.length;c<d;++c){if(!this.components[c].equals(a.components[c])){b=!1;break}}else b=!1;else b=!1;return b},transform:function(a,b){if(a&&b){for(var c=0,d=this.components.length;c<d;c++)this.components[c].transform(a,
b);this.bounds=null}return this},intersects:function(a){for(var b=!1,c=0,d=this.components.length;c<d&&!(b=a.intersects(this.components[c]));++c);return b},getVertices:function(a){for(var b=[],c=0,d=this.components.length;c<d;++c)Array.prototype.push.apply(b,this.components[c].getVertices(a));return b},CLASS_NAME:"OpenLayers.Geometry.Collection"});OpenLayers.Geometry.MultiPoint=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Point"],addPoint:function(a,b){this.addComponent(a,b)},removePoint:function(a){this.removeComponent(a)},CLASS_NAME:"OpenLayers.Geometry.MultiPoint"});OpenLayers.Geometry.Curve=OpenLayers.Class(OpenLayers.Geometry.MultiPoint,{componentTypes:["OpenLayers.Geometry.Point"],getLength:function(){var a=0;if(this.components&&1<this.components.length)for(var b=1,c=this.components.length;b<c;b++)a+=this.components[b-1].distanceTo(this.components[b]);return a},getGeodesicLength:function(a){var b=this;if(a){var c=new OpenLayers.Projection("EPSG:4326");c.equals(a)||(b=this.clone().transform(a,c))}a=0;if(b.components&&1<b.components.length)for(var d,e=1,f=b.components.length;e<
f;e++)c=b.components[e-1],d=b.components[e],a+=OpenLayers.Util.distVincenty({lon:c.x,lat:c.y},{lon:d.x,lat:d.y});return 1E3*a},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{removeComponent:function(a){var b=this.components&&2<this.components.length;b&&OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);return b},intersects:function(a){var b=!1,c=a.CLASS_NAME;if("OpenLayers.Geometry.LineString"==c||"OpenLayers.Geometry.LinearRing"==c||"OpenLayers.Geometry.Point"==c){var d=this.getSortedSegments();a="OpenLayers.Geometry.Point"==c?[{x1:a.x,y1:a.y,x2:a.x,y2:a.y}]:a.getSortedSegments();
var e,f,g,h,k,l,m,n=0,p=d.length;a:for(;n<p;++n){c=d[n];e=c.x1;f=c.x2;g=c.y1;h=c.y2;var q=0,r=a.length;for(;q<r;++q){k=a[q];if(k.x1>f)break;if(!(k.x2<e||(l=k.y1,m=k.y2,Math.min(l,m)>Math.max(g,h)||Math.max(l,m)<Math.min(g,h)||!OpenLayers.Geometry.segmentsIntersect(c,k)))){b=!0;break a}}}}else b=a.intersects(this);return b},getSortedSegments:function(){for(var a=this.components.length-1,b=Array(a),c,d,e=0;e<a;++e)c=this.components[e],d=this.components[e+1],b[e]=c.x<d.x?{x1:c.x,y1:c.y,x2:d.x,y2:d.y}:
{x1:d.x,y1:d.y,x2:c.x,y2:c.y};return b.sort(function(a,b){return a.x1-b.x1})},splitWithSegment:function(a,b){for(var c=!(b&&!1===b.edge),d=b&&b.tolerance,e=[],f=this.getVertices(),g=[],h=[],k=!1,l,m,n,p={point:!0,tolerance:d},q=null,r=0,s=f.length-2;r<=s;++r)if(d=f[r],g.push(d.clone()),l=f[r+1],m={x1:d.x,y1:d.y,x2:l.x,y2:l.y},m=OpenLayers.Geometry.segmentsIntersect(a,m,p),m instanceof OpenLayers.Geometry.Point&&((n=m.x===a.x1&&m.y===a.y1||m.x===a.x2&&m.y===a.y2||m.equals(d)||m.equals(l)?!0:!1)||c))m.equals(h[h.length-
1])||h.push(m.clone()),0===r&&m.equals(d)||m.equals(l)||(k=!0,m.equals(d)||g.push(m),e.push(new OpenLayers.Geometry.LineString(g)),g=[m.clone()]);k&&(g.push(l.clone()),e.push(new OpenLayers.Geometry.LineString(g)));if(0<h.length)var t=a.x1<a.x2?1:-1,u=a.y1<a.y2?1:-1,q={lines:e,points:h.sort(function(a,b){return t*a.x-t*b.x||u*a.y-u*b.y})};return q},split:function(a,b){var c=null,d=b&&b.mutual,e,f,g,h;if(a instanceof OpenLayers.Geometry.LineString){var k=this.getVertices(),l,m,n,p,q,r=[];g=[];for(var s=
0,t=k.length-2;s<=t;++s){l=k[s];m=k[s+1];n={x1:l.x,y1:l.y,x2:m.x,y2:m.y};h=h||[a];d&&r.push(l.clone());for(var u=0;u<h.length;++u)if(p=h[u].splitWithSegment(n,b))if(q=p.lines,0<q.length&&(q.unshift(u,1),Array.prototype.splice.apply(h,q),u+=q.length-2),d)for(var v=0,w=p.points.length;v<w;++v)q=p.points[v],q.equals(l)||(r.push(q),g.push(new OpenLayers.Geometry.LineString(r)),r=q.equals(m)?[]:[q.clone()])}d&&(0<g.length&&0<r.length)&&(r.push(m.clone()),g.push(new OpenLayers.Geometry.LineString(r)))}else c=
a.splitWith(this,b);h&&1<h.length?f=!0:h=[];g&&1<g.length?e=!0:g=[];if(f||e)c=d?[g,h]:h;return c},splitWith:function(a,b){return a.split(this,b)},getVertices:function(a){return!0===a?[this.components[0],this.components[this.components.length-1]]:!1===a?this.components.slice(1,this.components.length-1):this.components.slice()},distanceTo:function(a,b){var c=!(b&&!1===b.edge)&&b&&b.details,d,e={},f=Number.POSITIVE_INFINITY;if(a instanceof OpenLayers.Geometry.Point){for(var g=this.getSortedSegments(),
h=a.x,k=a.y,l,m=0,n=g.length;m<n;++m)if(l=g[m],d=OpenLayers.Geometry.distanceToSegment(a,l),d.distance<f){if(f=d.distance,e=d,0===f)break}else if(l.x2>h&&(k>l.y1&&k<l.y2||k<l.y1&&k>l.y2))break;e=c?{distance:e.distance,x0:e.x,y0:e.y,x1:h,y1:k}:e.distance}else if(a instanceof OpenLayers.Geometry.LineString){var g=this.getSortedSegments(),h=a.getSortedSegments(),p,q,r=h.length,s={point:!0},m=0,n=g.length;a:for(;m<n;++m){k=g[m];l=k.x1;q=k.y1;for(var t=0;t<r;++t)if(d=h[t],p=OpenLayers.Geometry.segmentsIntersect(k,
d,s)){f=0;e={distance:0,x0:p.x,y0:p.y,x1:p.x,y1:p.y};break a}else d=OpenLayers.Geometry.distanceToSegment({x:l,y:q},d),d.distance<f&&(f=d.distance,e={distance:f,x0:l,y0:q,x1:d.x,y1:d.y})}c||(e=e.distance);0!==f&&k&&(d=a.distanceTo(new OpenLayers.Geometry.Point(k.x2,k.y2),b),m=c?d.distance:d,m<f&&(e=c?{distance:f,x0:d.x1,y0:d.y1,x1:d.x0,y1:d.y0}:m))}else e=a.distanceTo(this,b),c&&(e={distance:e.distance,x0:e.x1,y0:e.y1,x1:e.x0,y1:e.y0});return e},simplify:function(a){if(this&&null!==this){var b=this.getVertices();
if(3>b.length)return this;var c=function(a,b,d,k){for(var l=0,m=0,n=b,p;n<d;n++){p=a[b];var q=a[d],r=a[n],r=Math.abs(0.5*(p.x*q.y+q.x*r.y+r.x*p.y-q.x*p.y-r.x*q.y-p.x*r.y));p=Math.sqrt(Math.pow(p.x-q.x,2)+Math.pow(p.y-q.y,2));p=2*(r/p);p>l&&(l=p,m=n)}l>k&&m!=b&&(e.push(m),c(a,b,m,k),c(a,m,d,k))},d=b.length-1,e=[];e.push(0);for(e.push(d);b[0].equals(b[d]);)d--,e.push(d);c(b,0,d,a);a=[];e.sort(function(a,b){return a-b});for(d=0;d<e.length;d++)a.push(b[e[d]]);return new OpenLayers.Geometry.LineString(a)}return this},
CLASS_NAME:"OpenLayers.Geometry.LineString"});OpenLayers.Geometry.MultiLineString=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LineString"],split:function(a,b){for(var c=null,d=b&&b.mutual,e,f,g,h,k=[],l=[a],m=0,n=this.components.length;m<n;++m){f=this.components[m];g=!1;for(var p=0;p<l.length;++p)if(e=f.split(l[p],b)){if(d){g=e[0];for(var q=0,r=g.length;q<r;++q)0===q&&k.length?k[k.length-1].addComponent(g[q]):k.push(new OpenLayers.Geometry.MultiLineString([g[q]]));g=!0;e=e[1]}if(e.length){e.unshift(p,
1);Array.prototype.splice.apply(l,e);break}}g||(k.length?k[k.length-1].addComponent(f.clone()):k=[new OpenLayers.Geometry.MultiLineString(f.clone())])}k&&1<k.length?g=!0:k=[];l&&1<l.length?h=!0:l=[];if(g||h)c=d?[k,l]:l;return c},splitWith:function(a,b){var c=null,d=b&&b.mutual,e,f,g,h,k,l;if(a instanceof OpenLayers.Geometry.LineString){l=[];k=[a];for(var m=0,n=this.components.length;m<n;++m){g=!1;f=this.components[m];for(var p=0;p<k.length;++p)if(e=k[p].split(f,b)){d&&(g=e[0],g.length&&(g.unshift(p,
1),Array.prototype.splice.apply(k,g),p+=g.length-2),e=e[1],0===e.length&&(e=[f.clone()]));g=0;for(var q=e.length;g<q;++g)0===g&&l.length?l[l.length-1].addComponent(e[g]):l.push(new OpenLayers.Geometry.MultiLineString([e[g]]));g=!0}g||(l.length?l[l.length-1].addComponent(f.clone()):l=[new OpenLayers.Geometry.MultiLineString([f.clone()])])}}else c=a.split(this);k&&1<k.length?h=!0:k=[];l&&1<l.length?g=!0:l=[];if(h||g)c=d?[k,l]:l;return c},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});OpenLayers.Geometry.LinearRing=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],addComponent:function(a,b){var c=!1,d=this.components.pop();null==b&&a.equals(d)||(c=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments));OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]]);return c},removeComponent:function(a){var b=this.components&&3<this.components.length;b&&(this.components.pop(),OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
arguments),OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]]));return b},move:function(a,b){for(var c=0,d=this.components.length;c<d-1;c++)this.components[c].move(a,b)},rotate:function(a,b){for(var c=0,d=this.components.length;c<d-1;++c)this.components[c].rotate(a,b)},resize:function(a,b,c){for(var d=0,e=this.components.length;d<e-1;++d)this.components[d].resize(a,b,c);return this},transform:function(a,b){if(a&&b){for(var c=0,d=this.components.length;c<d-1;c++)this.components[c].transform(a,
b);this.bounds=null}return this},getCentroid:function(){if(this.components){var a=this.components.length;if(0<a&&2>=a)return this.components[0].clone();if(2<a){var b=0,c=0,d=this.components[0].x,e=this.components[0].y,f=-1*this.getArea();if(0!=f){for(var g=0;g<a-1;g++)var h=this.components[g],k=this.components[g+1],b=b+(h.x+k.x-2*d)*((h.x-d)*(k.y-e)-(k.x-d)*(h.y-e)),c=c+(h.y+k.y-2*e)*((h.x-d)*(k.y-e)-(k.x-d)*(h.y-e));b=d+b/(6*f);a=e+c/(6*f)}else{for(g=0;g<a-1;g++)b+=this.components[g].x,c+=this.components[g].y;
b/=a-1;a=c/(a-1)}return new OpenLayers.Geometry.Point(b,a)}return null}},getArea:function(){var a=0;if(this.components&&2<this.components.length){for(var b=a=0,c=this.components.length;b<c-1;b++)var d=this.components[b],e=this.components[b+1],a=a+(d.x+e.x)*(e.y-d.y);a=-a/2}return a},getGeodesicArea:function(a){var b=this;if(a){var c=new OpenLayers.Projection("EPSG:4326");c.equals(a)||(b=this.clone().transform(a,c))}a=0;c=b.components&&b.components.length;if(2<c){for(var d,e,f=0;f<c-1;f++)d=b.components[f],
e=b.components[f+1],a+=OpenLayers.Util.rad(e.x-d.x)*(2+Math.sin(OpenLayers.Util.rad(d.y))+Math.sin(OpenLayers.Util.rad(e.y)));a=40680631590769*a/2}return a},containsPoint:function(a){var b=OpenLayers.Number.limitSigDigs,c=b(a.x,14);a=b(a.y,14);for(var d=this.components.length-1,e,f,g,h,k,l=0,m=0;m<d;++m)if(e=this.components[m],g=b(e.x,14),e=b(e.y,14),f=this.components[m+1],h=b(f.x,14),f=b(f.y,14),e==f){if(a==e&&(g<=h&&c>=g&&c<=h||g>=h&&c<=g&&c>=h)){l=-1;break}}else{k=b((a-f)*((h-g)/(f-e))+h,14);if(k==
c&&(e<f&&a>=e&&a<=f||e>f&&a<=e&&a>=f)){l=-1;break}k<=c||g!=h&&(k<Math.min(g,h)||k>Math.max(g,h))||(e<f&&a>=e&&a<f||e>f&&a<e&&a>=f)&&++l}return-1==l?1:!!(l&1)},intersects:function(a){var b=!1;if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.containsPoint(a);else if("OpenLayers.Geometry.LineString"==a.CLASS_NAME)b=a.intersects(this);else if("OpenLayers.Geometry.LinearRing"==a.CLASS_NAME)b=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[a]);else for(var c=0,d=a.components.length;c<
d&&!(b=a.components[c].intersects(this));++c);return b},getVertices:function(a){return!0===a?[]:this.components.slice(0,this.components.length-1)},CLASS_NAME:"OpenLayers.Geometry.LinearRing"});OpenLayers.Geometry.Polygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LinearRing"],getArea:function(){var a=0;if(this.components&&0<this.components.length)for(var a=a+Math.abs(this.components[0].getArea()),b=1,c=this.components.length;b<c;b++)a-=Math.abs(this.components[b].getArea());return a},getGeodesicArea:function(a){var b=0;if(this.components&&0<this.components.length)for(var b=b+Math.abs(this.components[0].getGeodesicArea(a)),c=1,d=this.components.length;c<
d;c++)b-=Math.abs(this.components[c].getGeodesicArea(a));return b},containsPoint:function(a){var b=this.components.length,c=!1;if(0<b&&(c=this.components[0].containsPoint(a),1!==c&&c&&1<b))for(var d,e=1;e<b;++e)if(d=this.components[e].containsPoint(a)){c=1===d?1:!1;break}return c},intersects:function(a){var b=!1,c,d;if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.containsPoint(a);else if("OpenLayers.Geometry.LineString"==a.CLASS_NAME||"OpenLayers.Geometry.LinearRing"==a.CLASS_NAME){c=0;for(d=
this.components.length;c<d&&!(b=a.intersects(this.components[c]));++c);if(!b)for(c=0,d=a.components.length;c<d&&!(b=this.containsPoint(a.components[c]));++c);}else for(c=0,d=a.components.length;c<d&&!(b=this.intersects(a.components[c]));++c);if(!b&&"OpenLayers.Geometry.Polygon"==a.CLASS_NAME){var e=this.components[0];c=0;for(d=e.components.length;c<d&&!(b=a.containsPoint(e.components[c]));++c);}return b},distanceTo:function(a,b){return b&&!1===b.edge&&this.intersects(a)?0:OpenLayers.Geometry.Collection.prototype.distanceTo.apply(this,
[a,b])},CLASS_NAME:"OpenLayers.Geometry.Polygon"});OpenLayers.Geometry.Polygon.createRegularPolygon=function(a,b,c,d){var e=Math.PI*(1/c-0.5);d&&(e+=d/180*Math.PI);for(var f,g=[],h=0;h<c;++h)f=e+2*h*Math.PI/c,d=a.x+b*Math.cos(f),f=a.y+b*Math.sin(f),g.push(new OpenLayers.Geometry.Point(d,f));a=new OpenLayers.Geometry.LinearRing(g);return new OpenLayers.Geometry.Polygon([a])};OpenLayers.Geometry.MultiPolygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Polygon"],CLASS_NAME:"OpenLayers.Geometry.MultiPolygon"});OpenLayers.Format.GML=OpenLayers.Class(OpenLayers.Format.XML,{featureNS:"http://mapserver.gis.umn.edu/mapserver",featurePrefix:"feature",featureName:"featureMember",layerName:"features",geometryName:"geometry",collectionName:"FeatureCollection",gmlns:"http://www.opengis.net/gml",extractAttributes:!0,xy:!0,initialize:function(a){this.regExes={trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g};OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==
typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a=this.getElementsByTagNameNS(a.documentElement,this.gmlns,this.featureName);for(var b=[],c=0;c<a.length;c++){var d=this.parseFeature(a[c]);d&&b.push(d)}return b},parseFeature:function(a){for(var b="MultiPolygon Polygon MultiLineString LineString MultiPoint Point Envelope".split(" "),c,d,e,f=0;f<b.length;++f)if(c=b[f],d=this.getElementsByTagNameNS(a,this.gmlns,c),0<d.length){if(e=this.parseGeometry[c.toLowerCase()])e=e.apply(this,
[d[0]]),this.internalProjection&&this.externalProjection&&e.transform(this.externalProjection,this.internalProjection);else throw new TypeError("Unsupported geometry type: "+c);break}var g;c=this.getElementsByTagNameNS(a,this.gmlns,"Box");for(f=0;f<c.length;++f)b=c[f],d=this.parseGeometry.box.apply(this,[b]),b=b.parentNode,"boundedBy"===(b.localName||b.nodeName.split(":").pop())?g=d:e=d.toGeometry();var h;this.extractAttributes&&(h=this.parseAttributes(a));h=new OpenLayers.Feature.Vector(e,h);h.bounds=
g;h.gml={featureType:a.firstChild.nodeName.split(":")[1],featureNS:a.firstChild.namespaceURI,featureNSPrefix:a.firstChild.prefix};a=a.firstChild;for(var k;a&&(1!=a.nodeType||!(k=a.getAttribute("fid")||a.getAttribute("id")));)a=a.nextSibling;h.fid=k;return h},parseGeometry:{point:function(a){var b,c;c=[];b=this.getElementsByTagNameNS(a,this.gmlns,"pos");0<b.length&&(c=b[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));0==c.length&&(b=this.getElementsByTagNameNS(a,
this.gmlns,"coordinates"),0<b.length&&(c=b[0].firstChild.nodeValue,c=c.replace(this.regExes.removeSpace,""),c=c.split(",")));0==c.length&&(b=this.getElementsByTagNameNS(a,this.gmlns,"coord"),0<b.length&&(a=this.getElementsByTagNameNS(b[0],this.gmlns,"X"),b=this.getElementsByTagNameNS(b[0],this.gmlns,"Y"),0<a.length&&0<b.length&&(c=[a[0].firstChild.nodeValue,b[0].firstChild.nodeValue])));2==c.length&&(c[2]=null);return this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],
c[0],c[2])},multipoint:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"Point");var b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.point.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiPoint(b)},linestring:function(a,b){var c,d;d=[];var e=[];c=this.getElementsByTagNameNS(a,this.gmlns,"posList");if(0<c.length){d=this.getChildValue(c[0]);d=d.replace(this.regExes.trimSpace,"");d=d.split(this.regExes.splitSpace);var f=parseInt(c[0].getAttribute("dimension")),
g,h,k;for(c=0;c<d.length/f;++c)g=c*f,h=d[g],k=d[g+1],g=2==f?null:d[g+2],this.xy?e.push(new OpenLayers.Geometry.Point(h,k,g)):e.push(new OpenLayers.Geometry.Point(k,h,g))}if(0==d.length&&(c=this.getElementsByTagNameNS(a,this.gmlns,"coordinates"),0<c.length))for(d=this.getChildValue(c[0]),d=d.replace(this.regExes.trimSpace,""),d=d.replace(this.regExes.trimComma,","),f=d.split(this.regExes.splitSpace),c=0;c<f.length;++c)d=f[c].split(","),2==d.length&&(d[2]=null),this.xy?e.push(new OpenLayers.Geometry.Point(d[0],
d[1],d[2])):e.push(new OpenLayers.Geometry.Point(d[1],d[0],d[2]));d=null;0!=e.length&&(d=b?new OpenLayers.Geometry.LinearRing(e):new OpenLayers.Geometry.LineString(e));return d},multilinestring:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"LineString");var b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.linestring.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiLineString(b)},polygon:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"LinearRing");
var b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.linestring.apply(this,[a[d],!0]))&&b.push(c);return new OpenLayers.Geometry.Polygon(b)},multipolygon:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"Polygon");var b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.polygon.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiPolygon(b)},envelope:function(a){var b=[],c,d,e=this.getElementsByTagNameNS(a,this.gmlns,"lowerCorner");if(0<e.length){c=
[];0<e.length&&(c=e[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));2==c.length&&(c[2]=null);var f=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}a=this.getElementsByTagNameNS(a,this.gmlns,"upperCorner");if(0<a.length){c=[];0<a.length&&(c=a[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));2==c.length&&(c[2]=null);var g=this.xy?new OpenLayers.Geometry.Point(c[0],
c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}f&&g&&(b.push(new OpenLayers.Geometry.Point(f.x,f.y)),b.push(new OpenLayers.Geometry.Point(g.x,f.y)),b.push(new OpenLayers.Geometry.Point(g.x,g.y)),b.push(new OpenLayers.Geometry.Point(f.x,g.y)),b.push(new OpenLayers.Geometry.Point(f.x,f.y)),b=new OpenLayers.Geometry.LinearRing(b),d=new OpenLayers.Geometry.Polygon([b]));return d},box:function(a){var b=this.getElementsByTagNameNS(a,this.gmlns,"coordinates"),c=a=null;0<b.length&&(b=b[0].firstChild.nodeValue,
b=b.split(" "),2==b.length&&(a=b[0].split(","),c=b[1].split(",")));if(null!==a&&null!==c)return new OpenLayers.Bounds(parseFloat(a[0]),parseFloat(a[1]),parseFloat(c[0]),parseFloat(c[1]))}},parseAttributes:function(a){var b={};a=a.firstChild;for(var c,d,e;a;){if(1==a.nodeType){a=a.childNodes;for(c=0;c<a.length;++c)if(d=a[c],1==d.nodeType)if(e=d.childNodes,1==e.length){if(e=e[0],3==e.nodeType||4==e.nodeType)d=d.prefix?d.nodeName.split(":")[1]:d.nodeName,e=e.nodeValue.replace(this.regExes.trimSpace,
""),b[d]=e}else b[d.nodeName.split(":").pop()]=null;break}a=a.nextSibling}return b},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=this.createElementNS("http://www.opengis.net/wfs","wfs:"+this.collectionName),c=0;c<a.length;c++)b.appendChild(this.createFeatureXML(a[c]));return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.featureNS,this.featurePrefix+":"+this.geometryName);c.appendChild(b);
var b=this.createElementNS(this.gmlns,"gml:"+this.featureName),d=this.createElementNS(this.featureNS,this.featurePrefix+":"+this.layerName);d.setAttribute("fid",a.fid||a.id);d.appendChild(c);for(var e in a.attributes){var c=this.createTextNode(a.attributes[e]),f=e.substring(e.lastIndexOf(":")+1),f=this.createElementNS(this.featureNS,this.featurePrefix+":"+f);f.appendChild(c);d.appendChild(f)}b.appendChild(d);return b},buildGeometryNode:function(a){this.externalProjection&&this.internalProjection&&
(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));var b=a.CLASS_NAME,b=b.substring(b.lastIndexOf(".")+1);return this.buildGeometry[b.toLowerCase()].apply(this,[a])},buildGeometry:{point:function(a){var b=this.createElementNS(this.gmlns,"gml:Point");b.appendChild(this.buildCoordinatesNode(a));return b},multipoint:function(a){var b=this.createElementNS(this.gmlns,"gml:MultiPoint");a=a.components;for(var c,d,e=0;e<a.length;e++)c=this.createElementNS(this.gmlns,"gml:pointMember"),
d=this.buildGeometry.point.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},linestring:function(a){var b=this.createElementNS(this.gmlns,"gml:LineString");b.appendChild(this.buildCoordinatesNode(a));return b},multilinestring:function(a){var b=this.createElementNS(this.gmlns,"gml:MultiLineString");a=a.components;for(var c,d,e=0;e<a.length;++e)c=this.createElementNS(this.gmlns,"gml:lineStringMember"),d=this.buildGeometry.linestring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);
return b},linearring:function(a){var b=this.createElementNS(this.gmlns,"gml:LinearRing");b.appendChild(this.buildCoordinatesNode(a));return b},polygon:function(a){var b=this.createElementNS(this.gmlns,"gml:Polygon");a=a.components;for(var c,d,e=0;e<a.length;++e)c=0==e?"outerBoundaryIs":"innerBoundaryIs",c=this.createElementNS(this.gmlns,"gml:"+c),d=this.buildGeometry.linearring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},multipolygon:function(a){var b=this.createElementNS(this.gmlns,
"gml:MultiPolygon");a=a.components;for(var c,d,e=0;e<a.length;++e)c=this.createElementNS(this.gmlns,"gml:polygonMember"),d=this.buildGeometry.polygon.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},bounds:function(a){var b=this.createElementNS(this.gmlns,"gml:Box");b.appendChild(this.buildCoordinatesNode(a));return b}},buildCoordinatesNode:function(a){var b=this.createElementNS(this.gmlns,"gml:coordinates");b.setAttribute("decimal",".");b.setAttribute("cs",",");b.setAttribute("ts",
" ");var c=[];if(a instanceof OpenLayers.Bounds)c.push(a.left+","+a.bottom),c.push(a.right+","+a.top);else{a=a.components?a.components:[a];for(var d=0;d<a.length;d++)c.push(a[d].x+","+a[d].y)}c=this.createTextNode(c.join(" "));b.appendChild(c);return b},CLASS_NAME:"OpenLayers.Format.GML"});OpenLayers.Format.GML||(OpenLayers.Format.GML={});
OpenLayers.Format.GML.Base=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs"},defaultPrefix:"gml",schemaLocation:null,featureType:null,featureNS:null,geometryName:"geometry",extractAttributes:!0,srsName:null,xy:!0,geometryTypes:null,singleFeatureType:null,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g,featureMember:/^(.*:)?featureMembers?$/},
initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.setGeometryTypes();a&&a.featureNS&&this.setNamespace("feature",a.featureNS);this.singleFeatureType=!a||"string"===typeof a.featureType},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b=[];this.readNode(a,{features:b},!0);if(0==b.length){var c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMember");if(c.length){a=
0;for(var d=c.length;a<d;++a)this.readNode(c[a],{features:b},!0)}else c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMembers"),c.length&&this.readNode(c[0],{features:b},!0)}return b},readNode:function(a,b,c){!0===c&&!0===this.autoConfig&&(this.featureType=null,delete this.namespaceAlias[this.featureNS],delete this.namespaces.feature,this.featureNS=null);this.featureNS||(a.prefix in this.namespaces||a.parentNode.namespaceURI!=this.namespaces.gml||!this.regExes.featureMember.test(a.parentNode.nodeName))||
(this.featureType=a.nodeName.split(":").pop(),this.setNamespace("feature",a.namespaceURI),this.featureNS=a.namespaceURI,this.autoConfig=!0);return OpenLayers.Format.XML.prototype.readNode.apply(this,[a,b])},readers:{gml:{_inherit:function(a,b,c){},featureMember:function(a,b){this.readChildNodes(a,b)},featureMembers:function(a,b){this.readChildNodes(a,b)},name:function(a,b){b.name=this.getChildValue(a)},boundedBy:function(a,b){var c={};this.readChildNodes(a,c);c.components&&0<c.components.length&&
(b.bounds=c.components[0])},Point:function(a,b){var c={points:[]};this.readChildNodes(a,c);b.components||(b.components=[]);b.components.push(c.points[0])},coordinates:function(a,b){for(var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace),d,e=c.length,f=Array(e),g=0;g<e;++g)d=c[g].split(","),f[g]=this.xy?new OpenLayers.Geometry.Point(d[0],d[1],d[2]):new OpenLayers.Geometry.Point(d[1],d[0],d[2]);b.points=f},coord:function(a,
b){var c={};this.readChildNodes(a,c);b.points||(b.points=[]);b.points.push(new OpenLayers.Geometry.Point(c.x,c.y,c.z))},X:function(a,b){b.x=this.getChildValue(a)},Y:function(a,b){b.y=this.getChildValue(a)},Z:function(a,b){b.z=this.getChildValue(a)},MultiPoint:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiPoint(c.components)]},pointMember:function(a,b){this.readChildNodes(a,b)},LineString:function(a,
b){var c={};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components||(b.components=[]);b.components.push(new OpenLayers.Geometry.LineString(c.points))},MultiLineString:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiLineString(c.components)]},lineStringMember:function(a,b){this.readChildNodes(a,b)},Polygon:function(a,b){var c={outer:null,inner:[]};this.readers.gml._inherit.apply(this,
[a,c,b]);this.readChildNodes(a,c);c.inner.unshift(c.outer);b.components||(b.components=[]);b.components.push(new OpenLayers.Geometry.Polygon(c.inner))},LinearRing:function(a,b){var c={};this.readers.gml._inherit.apply(this,[a,c]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.LinearRing(c.points)]},MultiPolygon:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiPolygon(c.components)]},
polygonMember:function(a,b){this.readChildNodes(a,b)},GeometryCollection:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.Collection(c.components)]},geometryMember:function(a,b){this.readChildNodes(a,b)}},feature:{"*":function(a,b){var c,d=a.localName||a.nodeName.split(":").pop();b.features?this.singleFeatureType||-1===OpenLayers.Util.indexOf(this.featureType,d)?d===this.featureType&&(c="_typeName"):c=
"_typeName":0==a.childNodes.length||1==a.childNodes.length&&3==a.firstChild.nodeType?this.extractAttributes&&(c="_attribute"):c="_geometry";c&&this.readers.feature[c].apply(this,[a,b])},_typeName:function(a,b){var c={components:[],attributes:{}};this.readChildNodes(a,c);c.name&&(c.attributes.name=c.name);var d=new OpenLayers.Feature.Vector(c.components[0],c.attributes);this.singleFeatureType||(d.type=a.nodeName.split(":").pop(),d.namespace=a.namespaceURI);var e=a.getAttribute("fid")||this.getAttributeNS(a,
this.namespaces.gml,"id");e&&(d.fid=e);this.internalProjection&&(this.externalProjection&&d.geometry)&&d.geometry.transform(this.externalProjection,this.internalProjection);c.bounds&&(d.bounds=c.bounds);b.features.push(d)},_geometry:function(a,b){this.geometryName||(this.geometryName=a.nodeName.split(":").pop());this.readChildNodes(a,b)},_attribute:function(a,b){var c=a.localName||a.nodeName.split(":").pop(),d=this.getChildValue(a);b.attributes[c]=d}},wfs:{FeatureCollection:function(a,b){this.readChildNodes(a,
b)}}},write:function(a){var b;b=OpenLayers.Util.isArray(a)?"featureMembers":"featureMember";a=this.writeNode("gml:"+b,a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:{featureMember:function(a){var b=this.createElementNSPlus("gml:featureMember");this.writeNode("feature:_typeName",a,b);return b},MultiPoint:function(a){var b=this.createElementNSPlus("gml:MultiPoint");a=a.components||[a];
for(var c=0,d=a.length;c<d;++c)this.writeNode("pointMember",a[c],b);return b},pointMember:function(a){var b=this.createElementNSPlus("gml:pointMember");this.writeNode("Point",a,b);return b},MultiLineString:function(a){var b=this.createElementNSPlus("gml:MultiLineString");a=a.components||[a];for(var c=0,d=a.length;c<d;++c)this.writeNode("lineStringMember",a[c],b);return b},lineStringMember:function(a){var b=this.createElementNSPlus("gml:lineStringMember");this.writeNode("LineString",a,b);return b},
MultiPolygon:function(a){var b=this.createElementNSPlus("gml:MultiPolygon");a=a.components||[a];for(var c=0,d=a.length;c<d;++c)this.writeNode("polygonMember",a[c],b);return b},polygonMember:function(a){var b=this.createElementNSPlus("gml:polygonMember");this.writeNode("Polygon",a,b);return b},GeometryCollection:function(a){for(var b=this.createElementNSPlus("gml:GeometryCollection"),c=0,d=a.components.length;c<d;++c)this.writeNode("geometryMember",a.components[c],b);return b},geometryMember:function(a){var b=
this.createElementNSPlus("gml:geometryMember");a=this.writeNode("feature:_geometry",a);b.appendChild(a.firstChild);return b}},feature:{_typeName:function(a){var b=this.createElementNSPlus("feature:"+this.featureType,{attributes:{fid:a.fid}});a.geometry&&this.writeNode("feature:_geometry",a.geometry,b);for(var c in a.attributes){var d=a.attributes[c];null!=d&&this.writeNode("feature:_attribute",{name:c,value:d},b)}return b},_geometry:function(a){this.externalProjection&&this.internalProjection&&(a=
a.clone().transform(this.internalProjection,this.externalProjection));var b=this.createElementNSPlus("feature:"+this.geometryName);a=this.writeNode("gml:"+this.geometryTypes[a.CLASS_NAME],a,b);this.srsName&&a.setAttribute("srsName",this.srsName);return b},_attribute:function(a){return this.createElementNSPlus("feature:"+a.name,{value:a.value})}},wfs:{FeatureCollection:function(a){for(var b=this.createElementNSPlus("wfs:FeatureCollection"),c=0,d=a.length;c<d;++c)this.writeNode("gml:featureMember",
a[c],b);return b}}},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":"LineString","OpenLayers.Geometry.MultiLineString":"MultiLineString","OpenLayers.Geometry.Polygon":"Polygon","OpenLayers.Geometry.MultiPolygon":"MultiPolygon","OpenLayers.Geometry.Collection":"GeometryCollection"}},CLASS_NAME:"OpenLayers.Format.GML.Base"});OpenLayers.Format.GML.v3=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd",curve:!1,multiCurve:!0,surface:!1,multiSurface:!0,initialize:function(a){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[a])},readers:{gml:OpenLayers.Util.applyDefaults({_inherit:function(a,b,c){if(a=parseInt(a.getAttribute("srsDimension"),10)||c&&c.srsDimension)b.srsDimension=a},featureMembers:function(a,
b){this.readChildNodes(a,b)},Curve:function(a,b){var c={points:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components||(b.components=[]);b.components.push(new OpenLayers.Geometry.LineString(c.points))},segments:function(a,b){this.readChildNodes(a,b)},LineStringSegment:function(a,b){var c={};this.readChildNodes(a,c);c.points&&Array.prototype.push.apply(b.points,c.points)},pos:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(this.regExes.splitSpace),
c=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2]);b.points=[c]},posList:function(a,b){for(var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(this.regExes.splitSpace),d=b.srsDimension||parseInt(a.getAttribute("srsDimension")||a.getAttribute("dimension"),10)||2,e,f,g,h=Array(c.length/d),k=0,l=c.length;k<l;k+=d)e=c[k],f=c[k+1],g=2==d?void 0:c[k+2],h[k/d]=this.xy?new OpenLayers.Geometry.Point(e,f,g):new OpenLayers.Geometry.Point(f,
e,g);b.points=h},Surface:function(a,b){this.readChildNodes(a,b)},patches:function(a,b){this.readChildNodes(a,b)},PolygonPatch:function(a,b){this.readers.gml.Polygon.apply(this,[a,b])},exterior:function(a,b){var c={};this.readChildNodes(a,c);b.outer=c.components[0]},interior:function(a,b){var c={};this.readChildNodes(a,c);b.inner.push(c.components[0])},MultiCurve:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);0<c.components.length&&(b.components=
[new OpenLayers.Geometry.MultiLineString(c.components)])},curveMember:function(a,b){this.readChildNodes(a,b)},MultiSurface:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);0<c.components.length&&(b.components=[new OpenLayers.Geometry.MultiPolygon(c.components)])},surfaceMember:function(a,b){this.readChildNodes(a,b)},surfaceMembers:function(a,b){this.readChildNodes(a,b)},pointMembers:function(a,b){this.readChildNodes(a,b)},lineStringMembers:function(a,
b){this.readChildNodes(a,b)},polygonMembers:function(a,b){this.readChildNodes(a,b)},geometryMembers:function(a,b){this.readChildNodes(a,b)},Envelope:function(a,b){var c={points:Array(2)};this.readChildNodes(a,c);b.components||(b.components=[]);var d=c.points[0],c=c.points[1];b.components.push(new OpenLayers.Bounds(d.x,d.y,c.x,c.y))},lowerCorner:function(a,b){var c={};this.readers.gml.pos.apply(this,[a,c]);b.points[0]=c.points[0]},upperCorner:function(a,b){var c={};this.readers.gml.pos.apply(this,
[a,c]);b.points[1]=c.points[0]}},OpenLayers.Format.GML.Base.prototype.readers.gml),feature:OpenLayers.Format.GML.Base.prototype.readers.feature,wfs:OpenLayers.Format.GML.Base.prototype.readers.wfs},write:function(a){var b;b=OpenLayers.Util.isArray(a)?"featureMembers":"featureMember";a=this.writeNode("gml:"+b,a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:OpenLayers.Util.applyDefaults({featureMembers:function(a){for(var b=
this.createElementNSPlus("gml:featureMembers"),c=0,d=a.length;c<d;++c)this.writeNode("feature:_typeName",a[c],b);return b},Point:function(a){var b=this.createElementNSPlus("gml:Point");this.writeNode("pos",a,b);return b},pos:function(a){return this.createElementNSPlus("gml:pos",{value:this.xy?a.x+" "+a.y:a.y+" "+a.x})},LineString:function(a){var b=this.createElementNSPlus("gml:LineString");this.writeNode("posList",a.components,b);return b},Curve:function(a){var b=this.createElementNSPlus("gml:Curve");
this.writeNode("segments",a,b);return b},segments:function(a){var b=this.createElementNSPlus("gml:segments");this.writeNode("LineStringSegment",a,b);return b},LineStringSegment:function(a){var b=this.createElementNSPlus("gml:LineStringSegment");this.writeNode("posList",a.components,b);return b},posList:function(a){for(var b=a.length,c=Array(b),d,e=0;e<b;++e)d=a[e],c[e]=this.xy?d.x+" "+d.y:d.y+" "+d.x;return this.createElementNSPlus("gml:posList",{value:c.join(" ")})},Surface:function(a){var b=this.createElementNSPlus("gml:Surface");
this.writeNode("patches",a,b);return b},patches:function(a){var b=this.createElementNSPlus("gml:patches");this.writeNode("PolygonPatch",a,b);return b},PolygonPatch:function(a){var b=this.createElementNSPlus("gml:PolygonPatch",{attributes:{interpolation:"planar"}});this.writeNode("exterior",a.components[0],b);for(var c=1,d=a.components.length;c<d;++c)this.writeNode("interior",a.components[c],b);return b},Polygon:function(a){var b=this.createElementNSPlus("gml:Polygon");this.writeNode("exterior",a.components[0],
b);for(var c=1,d=a.components.length;c<d;++c)this.writeNode("interior",a.components[c],b);return b},exterior:function(a){var b=this.createElementNSPlus("gml:exterior");this.writeNode("LinearRing",a,b);return b},interior:function(a){var b=this.createElementNSPlus("gml:interior");this.writeNode("LinearRing",a,b);return b},LinearRing:function(a){var b=this.createElementNSPlus("gml:LinearRing");this.writeNode("posList",a.components,b);return b},MultiCurve:function(a){var b=this.createElementNSPlus("gml:MultiCurve");
a=a.components||[a];for(var c=0,d=a.length;c<d;++c)this.writeNode("curveMember",a[c],b);return b},curveMember:function(a){var b=this.createElementNSPlus("gml:curveMember");this.curve?this.writeNode("Curve",a,b):this.writeNode("LineString",a,b);return b},MultiSurface:function(a){var b=this.createElementNSPlus("gml:MultiSurface");a=a.components||[a];for(var c=0,d=a.length;c<d;++c)this.writeNode("surfaceMember",a[c],b);return b},surfaceMember:function(a){var b=this.createElementNSPlus("gml:surfaceMember");
this.surface?this.writeNode("Surface",a,b):this.writeNode("Polygon",a,b);return b},Envelope:function(a){var b=this.createElementNSPlus("gml:Envelope");this.writeNode("lowerCorner",a,b);this.writeNode("upperCorner",a,b);this.srsName&&b.setAttribute("srsName",this.srsName);return b},lowerCorner:function(a){return this.createElementNSPlus("gml:lowerCorner",{value:this.xy?a.left+" "+a.bottom:a.bottom+" "+a.left})},upperCorner:function(a){return this.createElementNSPlus("gml:upperCorner",{value:this.xy?
a.right+" "+a.top:a.top+" "+a.right})}},OpenLayers.Format.GML.Base.prototype.writers.gml),feature:OpenLayers.Format.GML.Base.prototype.writers.feature,wfs:OpenLayers.Format.GML.Base.prototype.writers.wfs},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":!0===this.curve?"Curve":"LineString","OpenLayers.Geometry.MultiLineString":!1===this.multiCurve?"MultiLineString":"MultiCurve","OpenLayers.Geometry.Polygon":!0===
this.surface?"Surface":"Polygon","OpenLayers.Geometry.MultiPolygon":!1===this.multiSurface?"MultiPolygon":"MultiSurface","OpenLayers.Geometry.Collection":"GeometryCollection"}},CLASS_NAME:"OpenLayers.Format.GML.v3"});OpenLayers.Format.Filter.v1_1_0=OpenLayers.Class(OpenLayers.Format.GML.v3,OpenLayers.Format.Filter.v1,{VERSION:"1.1.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.1.0/filter.xsd",initialize:function(a){OpenLayers.Format.GML.v3.prototype.initialize.apply(this,[a])},readers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a,b){var c=a.getAttribute("matchCase"),c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,matchCase:!("false"===c||"0"===c)});this.readChildNodes(a,
c);b.filters.push(c)},PropertyIsNotEqualTo:function(a,b){var c=a.getAttribute("matchCase"),c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO,matchCase:!("false"===c||"0"===c)});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLike:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(a,c);var d=a.getAttribute("wildCard"),e=a.getAttribute("singleChar"),f=a.getAttribute("escapeChar");c.value2regex(d,e,
f);b.filters.push(c)}},OpenLayers.Format.Filter.v1.prototype.readers.ogc),gml:OpenLayers.Format.GML.v3.prototype.readers.gml,feature:OpenLayers.Format.GML.v3.prototype.readers.feature},writers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsEqualTo",{attributes:{matchCase:a.matchCase}});this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsNotEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsNotEqualTo",
{attributes:{matchCase:a.matchCase}});this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLike:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLike",{attributes:{matchCase:a.matchCase,wildCard:"*",singleChar:".",escapeChar:"!"}});this.writeNode("PropertyName",a,b);this.writeNode("Literal",a.regex2value(),b);return b},BBOX:function(a){var b=this.createElementNSPlus("ogc:BBOX");a.property&&this.writeNode("PropertyName",a,b);var c=this.writeNode("gml:Envelope",
a.value);a.projection&&c.setAttribute("srsName",a.projection);b.appendChild(c);return b},SortBy:function(a){for(var b=this.createElementNSPlus("ogc:SortBy"),c=0,d=a.length;c<d;c++)this.writeNode("ogc:SortProperty",a[c],b);return b},SortProperty:function(a){var b=this.createElementNSPlus("ogc:SortProperty");this.writeNode("ogc:PropertyName",a,b);this.writeNode("ogc:SortOrder","DESC"==a.order?"DESC":"ASC",b);return b},SortOrder:function(a){return this.createElementNSPlus("ogc:SortOrder",{value:a})}},
OpenLayers.Format.Filter.v1.prototype.writers.ogc),gml:OpenLayers.Format.GML.v3.prototype.writers.gml,feature:OpenLayers.Format.GML.v3.prototype.writers.feature},writeSpatial:function(a,b){var c=this.createElementNSPlus("ogc:"+b);this.writeNode("PropertyName",a,c);if(a.value instanceof OpenLayers.Filter.Function)this.writeNode("Function",a.value,c);else{var d;d=a.value instanceof OpenLayers.Geometry?this.writeNode("feature:_geometry",a.value).firstChild:this.writeNode("gml:Envelope",a.value);a.projection&&
d.setAttribute("srsName",a.projection);c.appendChild(d)}return c},CLASS_NAME:"OpenLayers.Format.Filter.v1_1_0"});OpenLayers.Format.OWSCommon=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",getVersion:function(a,b){var c=this.version;if(!c){var d=a.getAttribute("xmlns:ows");d&&"1.1"===d.substring(d.lastIndexOf("/")+1)&&(c="1.1.0");c||(c=this.defaultVersion)}return c},CLASS_NAME:"OpenLayers.Format.OWSCommon"});OpenLayers.Format.OWSCommon.v1=OpenLayers.Class(OpenLayers.Format.XML,{regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a,b){OpenLayers.Util.applyDefaults(b,this.options);var c={};this.readChildNodes(a,c);return c},readers:{ows:{Exception:function(a,b){var c={code:a.getAttribute("exceptionCode"),locator:a.getAttribute("locator"),texts:[]};b.exceptions.push(c);this.readChildNodes(a,c)},ExceptionText:function(a,b){var c=this.getChildValue(a);b.texts.push(c)},
ServiceIdentification:function(a,b){b.serviceIdentification={};this.readChildNodes(a,b.serviceIdentification)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b["abstract"]=this.getChildValue(a)},Keywords:function(a,b){b.keywords={};this.readChildNodes(a,b.keywords)},Keyword:function(a,b){b[this.getChildValue(a)]=!0},ServiceType:function(a,b){b.serviceType={codeSpace:a.getAttribute("codeSpace"),value:this.getChildValue(a)}},ServiceTypeVersion:function(a,b){b.serviceTypeVersion=
this.getChildValue(a)},Fees:function(a,b){b.fees=this.getChildValue(a)},AccessConstraints:function(a,b){b.accessConstraints=this.getChildValue(a)},ServiceProvider:function(a,b){b.serviceProvider={};this.readChildNodes(a,b.serviceProvider)},ProviderName:function(a,b){b.providerName=this.getChildValue(a)},ProviderSite:function(a,b){b.providerSite=this.getAttributeNS(a,this.namespaces.xlink,"href")},ServiceContact:function(a,b){b.serviceContact={};this.readChildNodes(a,b.serviceContact)},IndividualName:function(a,
b){b.individualName=this.getChildValue(a)},PositionName:function(a,b){b.positionName=this.getChildValue(a)},ContactInfo:function(a,b){b.contactInfo={};this.readChildNodes(a,b.contactInfo)},Phone:function(a,b){b.phone={};this.readChildNodes(a,b.phone)},Voice:function(a,b){b.voice=this.getChildValue(a)},Address:function(a,b){b.address={};this.readChildNodes(a,b.address)},DeliveryPoint:function(a,b){b.deliveryPoint=this.getChildValue(a)},City:function(a,b){b.city=this.getChildValue(a)},AdministrativeArea:function(a,
b){b.administrativeArea=this.getChildValue(a)},PostalCode:function(a,b){b.postalCode=this.getChildValue(a)},Country:function(a,b){b.country=this.getChildValue(a)},ElectronicMailAddress:function(a,b){b.electronicMailAddress=this.getChildValue(a)},Role:function(a,b){b.role=this.getChildValue(a)},OperationsMetadata:function(a,b){b.operationsMetadata={};this.readChildNodes(a,b.operationsMetadata)},Operation:function(a,b){var c=a.getAttribute("name");b[c]={};this.readChildNodes(a,b[c])},DCP:function(a,
b){b.dcp={};this.readChildNodes(a,b.dcp)},HTTP:function(a,b){b.http={};this.readChildNodes(a,b.http)},Get:function(a,b){b.get||(b.get=[]);var c={url:this.getAttributeNS(a,this.namespaces.xlink,"href")};this.readChildNodes(a,c);b.get.push(c)},Post:function(a,b){b.post||(b.post=[]);var c={url:this.getAttributeNS(a,this.namespaces.xlink,"href")};this.readChildNodes(a,c);b.post.push(c)},Parameter:function(a,b){b.parameters||(b.parameters={});var c=a.getAttribute("name");b.parameters[c]={};this.readChildNodes(a,
b.parameters[c])},Constraint:function(a,b){b.constraints||(b.constraints={});var c=a.getAttribute("name");b.constraints[c]={};this.readChildNodes(a,b.constraints[c])},Value:function(a,b){b[this.getChildValue(a)]=!0},OutputFormat:function(a,b){b.formats.push({value:this.getChildValue(a)});this.readChildNodes(a,b)},WGS84BoundingBox:function(a,b){var c={};c.crs=a.getAttribute("crs");b.BoundingBox?b.BoundingBox.push(c):(b.projection=c.crs,c=b);this.readChildNodes(a,c)},BoundingBox:function(a,b){this.readers.ows.WGS84BoundingBox.apply(this,
[a,b])},LowerCorner:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace);b.left=c[0];b.bottom=c[1]},UpperCorner:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace);b.right=c[0];b.top=c[1];b.bounds=new OpenLayers.Bounds(b.left,b.bottom,b.right,b.top);delete b.left;delete b.bottom;delete b.right;delete b.top},
Language:function(a,b){b.language=this.getChildValue(a)}}},writers:{ows:{BoundingBox:function(a,b){var c=this.createElementNSPlus(b||"ows:BoundingBox",{attributes:{crs:a.projection}});this.writeNode("ows:LowerCorner",a,c);this.writeNode("ows:UpperCorner",a,c);return c},LowerCorner:function(a){return this.createElementNSPlus("ows:LowerCorner",{value:a.bounds.left+" "+a.bounds.bottom})},UpperCorner:function(a){return this.createElementNSPlus("ows:UpperCorner",{value:a.bounds.right+" "+a.bounds.top})},
Identifier:function(a){return this.createElementNSPlus("ows:Identifier",{value:a})},Title:function(a){return this.createElementNSPlus("ows:Title",{value:a})},Abstract:function(a){return this.createElementNSPlus("ows:Abstract",{value:a})},OutputFormat:function(a){return this.createElementNSPlus("ows:OutputFormat",{value:a})}}},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1"});OpenLayers.Format.OWSCommon.v1_0_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1,{namespaces:{ows:"http://www.opengis.net/ows",xlink:"http://www.w3.org/1999/xlink"},readers:{ows:OpenLayers.Util.applyDefaults({ExceptionReport:function(a,b){b.success=!1;b.exceptionReport={version:a.getAttribute("version"),language:a.getAttribute("language"),exceptions:[]};this.readChildNodes(a,b.exceptionReport)}},OpenLayers.Format.OWSCommon.v1.prototype.readers.ows)},writers:{ows:OpenLayers.Format.OWSCommon.v1.prototype.writers.ows},
CLASS_NAME:"OpenLayers.Format.OWSCommon.v1_0_0"});OpenLayers.Format.WFST.v1_1_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_1_0,OpenLayers.Format.WFST.v1,{version:"1.1.0",schemaLocations:{wfs:"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"},initialize:function(a){OpenLayers.Format.Filter.v1_1_0.prototype.initialize.apply(this,[a]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[a])},readNode:function(a,b,c){return OpenLayers.Format.GML.v3.prototype.readNode.apply(this,arguments)},readers:{wfs:OpenLayers.Util.applyDefaults({FeatureCollection:function(a,
b){b.numberOfFeatures=parseInt(a.getAttribute("numberOfFeatures"));OpenLayers.Format.WFST.v1.prototype.readers.wfs.FeatureCollection.apply(this,arguments)},TransactionResponse:function(a,b){b.insertIds=[];b.success=!1;this.readChildNodes(a,b)},TransactionSummary:function(a,b){b.success=!0},InsertResults:function(a,b){this.readChildNodes(a,b)},Feature:function(a,b){var c={fids:[]};this.readChildNodes(a,c);b.insertIds.push(c.fids[0])}},OpenLayers.Format.WFST.v1.prototype.readers.wfs),gml:OpenLayers.Format.GML.v3.prototype.readers.gml,
feature:OpenLayers.Format.GML.v3.prototype.readers.feature,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.readers.ogc,ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows},writers:{wfs:OpenLayers.Util.applyDefaults({GetFeature:function(a){var b=OpenLayers.Format.WFST.v1.prototype.writers.wfs.GetFeature.apply(this,arguments);a&&this.setAttributes(b,{resultType:a.resultType,startIndex:a.startIndex,count:a.count});return b},Query:function(a){a=OpenLayers.Util.extend({featureNS:this.featureNS,
featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName},a);var b=a.featurePrefix,c=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(b?b+":":"")+a.featureType,srsName:a.srsName}});a.featureNS&&c.setAttribute("xmlns:"+b,a.featureNS);if(a.propertyNames)for(var b=0,d=a.propertyNames.length;b<d;b++)this.writeNode("wfs:PropertyName",{property:a.propertyNames[b]},c);a.filter&&(OpenLayers.Format.WFST.v1_1_0.prototype.setFilterProperty.call(this,a.filter),this.writeNode("ogc:Filter",
a.filter,c));return c},PropertyName:function(a){return this.createElementNSPlus("wfs:PropertyName",{value:a.property})}},OpenLayers.Format.WFST.v1.prototype.writers.wfs),gml:OpenLayers.Format.GML.v3.prototype.writers.gml,feature:OpenLayers.Format.GML.v3.prototype.writers.feature,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc},CLASS_NAME:"OpenLayers.Format.WFST.v1_1_0"});OpenLayers.Protocol=OpenLayers.Class({format:null,options:null,autoDestroy:!0,defaultFilter:null,initialize:function(a){a=a||{};OpenLayers.Util.extend(this,a);this.options=a},mergeWithDefaultFilter:function(a){return a&&this.defaultFilter?new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.defaultFilter,a]}):a||this.defaultFilter||void 0},destroy:function(){this.format=this.options=null},read:function(a){a=a||{};a.filter=this.mergeWithDefaultFilter(a.filter)},create:function(){},
update:function(){},"delete":function(){},commit:function(){},abort:function(a){},createCallback:function(a,b,c){return OpenLayers.Function.bind(function(){a.apply(this,[b,c])},this)},CLASS_NAME:"OpenLayers.Protocol"});OpenLayers.Protocol.Response=OpenLayers.Class({code:null,requestType:null,last:!0,features:null,data:null,reqFeatures:null,priv:null,error:null,initialize:function(a){OpenLayers.Util.extend(this,a)},success:function(){return 0<this.code},CLASS_NAME:"OpenLayers.Protocol.Response"});
OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;OpenLayers.Format.JSON=OpenLayers.Class(OpenLayers.Format,{indent:"    ",space:" ",newline:"\n",level:0,pretty:!1,nativeJSON:function(){return!(!window.JSON||"function"!=typeof JSON.parse||"function"!=typeof JSON.stringify)}(),read:function(a,b){var c;if(this.nativeJSON)c=JSON.parse(a,b);else try{if(/^[\],:{}\s]*$/.test(a.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))&&(c=eval("("+a+")"),"function"===
typeof b)){var d=function(a,c){if(c&&"object"===typeof c)for(var e in c)c.hasOwnProperty(e)&&(c[e]=d(e,c[e]));return b(a,c)};c=d("",c)}}catch(e){}this.keepData&&(this.data=c);return c},write:function(a,b){this.pretty=!!b;var c=null,d=typeof a;if(this.serialize[d])try{c=!this.pretty&&this.nativeJSON?JSON.stringify(a):this.serialize[d].apply(this,[a])}catch(e){OpenLayers.Console.error("Trouble serializing: "+e)}return c},writeIndent:function(){var a=[];if(this.pretty)for(var b=0;b<this.level;++b)a.push(this.indent);
return a.join("")},writeNewline:function(){return this.pretty?this.newline:""},writeSpace:function(){return this.pretty?this.space:""},serialize:{object:function(a){if(null==a)return"null";if(a.constructor==Date)return this.serialize.date.apply(this,[a]);if(a.constructor==Array)return this.serialize.array.apply(this,[a]);var b=["{"];this.level+=1;var c,d,e,f=!1;for(c in a)a.hasOwnProperty(c)&&(d=OpenLayers.Format.JSON.prototype.write.apply(this,[c,this.pretty]),e=OpenLayers.Format.JSON.prototype.write.apply(this,
[a[c],this.pretty]),null!=d&&null!=e&&(f&&b.push(","),b.push(this.writeNewline(),this.writeIndent(),d,":",this.writeSpace(),e),f=!0));this.level-=1;b.push(this.writeNewline(),this.writeIndent(),"}");return b.join("")},array:function(a){var b,c=["["];this.level+=1;for(var d=0,e=a.length;d<e;++d)b=OpenLayers.Format.JSON.prototype.write.apply(this,[a[d],this.pretty]),null!=b&&(0<d&&c.push(","),c.push(this.writeNewline(),this.writeIndent(),b));this.level-=1;c.push(this.writeNewline(),this.writeIndent(),
"]");return c.join("")},string:function(a){var b={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};return/["\\\x00-\x1f]/.test(a)?'"'+a.replace(/([\x00-\x1f\\"])/g,function(a,d){var e=b[d];if(e)return e;e=d.charCodeAt();return"\\u00"+Math.floor(e/16).toString(16)+(e%16).toString(16)})+'"':'"'+a+'"'},number:function(a){return isFinite(a)?String(a):"null"},"boolean":function(a){return String(a)},date:function(a){function b(a){return 10>a?"0"+a:a}return'"'+a.getFullYear()+
"-"+b(a.getMonth()+1)+"-"+b(a.getDate())+"T"+b(a.getHours())+":"+b(a.getMinutes())+":"+b(a.getSeconds())+'"'}},CLASS_NAME:"OpenLayers.Format.JSON"});OpenLayers.Format.GeoJSON=OpenLayers.Class(OpenLayers.Format.JSON,{ignoreExtraDims:!1,read:function(a,b,c){b=b?b:"FeatureCollection";var d=null,e=null,e="string"==typeof a?OpenLayers.Format.JSON.prototype.read.apply(this,[a,c]):a;if(!e)OpenLayers.Console.error("Bad JSON: "+a);else if("string"!=typeof e.type)OpenLayers.Console.error("Bad GeoJSON - no type: "+a);else if(this.isValidType(e,b))switch(b){case "Geometry":try{d=this.parseGeometry(e)}catch(f){OpenLayers.Console.error(f)}break;case "Feature":try{d=
this.parseFeature(e),d.type="Feature"}catch(g){OpenLayers.Console.error(g)}break;case "FeatureCollection":switch(d=[],e.type){case "Feature":try{d.push(this.parseFeature(e))}catch(h){d=null,OpenLayers.Console.error(h)}break;case "FeatureCollection":a=0;for(b=e.features.length;a<b;++a)try{d.push(this.parseFeature(e.features[a]))}catch(k){d=null,OpenLayers.Console.error(k)}break;default:try{var l=this.parseGeometry(e);d.push(new OpenLayers.Feature.Vector(l))}catch(m){d=null,OpenLayers.Console.error(m)}}}return d},
isValidType:function(a,b){var c=!1;switch(b){case "Geometry":-1==OpenLayers.Util.indexOf("Point MultiPoint LineString MultiLineString Polygon MultiPolygon Box GeometryCollection".split(" "),a.type)?OpenLayers.Console.error("Unsupported geometry type: "+a.type):c=!0;break;case "FeatureCollection":c=!0;break;default:a.type==b?c=!0:OpenLayers.Console.error("Cannot convert types from "+a.type+" to "+b)}return c},parseFeature:function(a){var b,c,d;c=a.properties?a.properties:{};d=a.geometry&&a.geometry.bbox||
a.bbox;try{b=this.parseGeometry(a.geometry)}catch(e){throw e;}b=new OpenLayers.Feature.Vector(b,c);d&&(b.bounds=OpenLayers.Bounds.fromArray(d));a.id&&(b.fid=a.id);return b},parseGeometry:function(a){if(null==a)return null;var b,c=!1;if("GeometryCollection"==a.type){if(!OpenLayers.Util.isArray(a.geometries))throw"GeometryCollection must have geometries array: "+a;b=a.geometries.length;for(var c=Array(b),d=0;d<b;++d)c[d]=this.parseGeometry.apply(this,[a.geometries[d]]);b=new OpenLayers.Geometry.Collection(c);
c=!0}else{if(!OpenLayers.Util.isArray(a.coordinates))throw"Geometry must have coordinates array: "+a;if(!this.parseCoords[a.type.toLowerCase()])throw"Unsupported geometry type: "+a.type;try{b=this.parseCoords[a.type.toLowerCase()].apply(this,[a.coordinates])}catch(e){throw e;}}this.internalProjection&&(this.externalProjection&&!c)&&b.transform(this.externalProjection,this.internalProjection);return b},parseCoords:{point:function(a){if(!1==this.ignoreExtraDims&&2!=a.length)throw"Only 2D points are supported: "+
a;return new OpenLayers.Geometry.Point(a[0],a[1])},multipoint:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.point.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiPoint(b)},linestring:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.point.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.LineString(b)},multilinestring:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=
this.parseCoords.linestring.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiLineString(b)},polygon:function(a){for(var b=[],c,d,e=0,f=a.length;e<f;++e){try{d=this.parseCoords.linestring.apply(this,[a[e]])}catch(g){throw g;}c=new OpenLayers.Geometry.LinearRing(d.components);b.push(c)}return new OpenLayers.Geometry.Polygon(b)},multipolygon:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.polygon.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiPolygon(b)},
box:function(a){if(2!=a.length)throw"GeoJSON box coordinates must have 2 elements";return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(a[0][0],a[0][1]),new OpenLayers.Geometry.Point(a[1][0],a[0][1]),new OpenLayers.Geometry.Point(a[1][0],a[1][1]),new OpenLayers.Geometry.Point(a[0][0],a[1][1]),new OpenLayers.Geometry.Point(a[0][0],a[0][1])])])}},write:function(a,b){var c={type:null};if(OpenLayers.Util.isArray(a)){c.type="FeatureCollection";var d=
a.length;c.features=Array(d);for(var e=0;e<d;++e){var f=a[e];if(!f instanceof OpenLayers.Feature.Vector)throw"FeatureCollection only supports collections of features: "+f;c.features[e]=this.extract.feature.apply(this,[f])}}else 0==a.CLASS_NAME.indexOf("OpenLayers.Geometry")?c=this.extract.geometry.apply(this,[a]):a instanceof OpenLayers.Feature.Vector&&(c=this.extract.feature.apply(this,[a]),a.layer&&a.layer.projection&&(c.crs=this.createCRSObject(a)));return OpenLayers.Format.JSON.prototype.write.apply(this,
[c,b])},createCRSObject:function(a){a=a.layer.projection.toString();var b={};a.match(/epsg:/i)&&(a=parseInt(a.substring(a.indexOf(":")+1)),b=4326==a?{type:"name",properties:{name:"urn:ogc:def:crs:OGC:1.3:CRS84"}}:{type:"name",properties:{name:"EPSG:"+a}});return b},extract:{feature:function(a){var b=this.extract.geometry.apply(this,[a.geometry]),b={type:"Feature",properties:a.attributes,geometry:b};null!=a.fid&&(b.id=a.fid);return b},geometry:function(a){if(null==a)return null;this.internalProjection&&
this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));var b=a.CLASS_NAME.split(".")[2];a=this.extract[b.toLowerCase()].apply(this,[a]);return"Collection"==b?{type:"GeometryCollection",geometries:a}:{type:b,coordinates:a}},point:function(a){return[a.x,a.y]},multipoint:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b},linestring:function(a){for(var b=[],c=0,d=a.components.length;c<
d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b},multilinestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.linestring.apply(this,[a.components[c]]));return b},polygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.linestring.apply(this,[a.components[c]]));return b},multipolygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.polygon.apply(this,[a.components[c]]));return b},collection:function(a){for(var b=
a.components.length,c=Array(b),d=0;d<b;++d)c[d]=this.extract.geometry.apply(this,[a.components[d]]);return c}},CLASS_NAME:"OpenLayers.Format.GeoJSON"});OpenLayers.Protocol.Script=OpenLayers.Class(OpenLayers.Protocol,{url:null,params:null,callback:null,callbackTemplate:"OpenLayers.Protocol.Script.registry.${id}",callbackKey:"callback",callbackPrefix:"",scope:null,format:null,pendingRequests:null,srsInBBOX:!1,initialize:function(a){a=a||{};this.params={};this.pendingRequests={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);this.format||(this.format=new OpenLayers.Format.GeoJSON);if(!this.filterToParams&&OpenLayers.Format.QueryStringFilter){var b=
new OpenLayers.Format.QueryStringFilter({srsInBBOX:this.srsInBBOX});this.filterToParams=function(a,d){return b.write(a,d)}}},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=OpenLayers.Util.applyDefaults(a,this.options);a.params=OpenLayers.Util.applyDefaults(a.params,this.options.params);a.filter&&this.filterToParams&&(a.params=this.filterToParams(a.filter,a.params));var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.createRequest(a.url,a.params,OpenLayers.Function.bind(function(c){b.data=
c;this.handleRead(b,a)},this));b.priv=c;return b},createRequest:function(a,b,c){c=OpenLayers.Protocol.Script.register(c);var d=OpenLayers.String.format(this.callbackTemplate,{id:c});b=OpenLayers.Util.extend({},b);b[this.callbackKey]=this.callbackPrefix+d;a=OpenLayers.Util.urlAppend(a,OpenLayers.Util.getParameterString(b));b=document.createElement("script");b.type="text/javascript";b.src=a;b.id="OpenLayers_Protocol_Script_"+c;this.pendingRequests[b.id]=b;document.getElementsByTagName("head")[0].appendChild(b);
return b},destroyRequest:function(a){OpenLayers.Protocol.Script.unregister(a.id.split("_").pop());delete this.pendingRequests[a.id];a.parentNode&&a.parentNode.removeChild(a)},handleRead:function(a,b){this.handleResponse(a,b)},handleResponse:function(a,b){b.callback&&(a.data?(a.features=this.parseFeatures(a.data),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE,this.destroyRequest(a.priv),b.callback.call(b.scope,a))},parseFeatures:function(a){return this.format.read(a)},
abort:function(a){if(a)this.destroyRequest(a.priv);else for(var b in this.pendingRequests)this.destroyRequest(this.pendingRequests[b])},destroy:function(){this.abort();delete this.params;delete this.format;OpenLayers.Protocol.prototype.destroy.apply(this)},CLASS_NAME:"OpenLayers.Protocol.Script"});(function(){var a=OpenLayers.Protocol.Script,b=0;a.registry={};a.register=function(c){var d="c"+ ++b;a.registry[d]=function(){c.apply(this,arguments)};return d};a.unregister=function(b){delete a.registry[b]}})();OpenLayers.Format.EncodedPolyline=OpenLayers.Class(OpenLayers.Format,{geometryType:"linestring",initialize:function(a){OpenLayers.Format.prototype.initialize.apply(this,[a])},read:function(a){var b;if("linestring"==this.geometryType)b=OpenLayers.Geometry.LineString;else if("linearring"==this.geometryType)b=OpenLayers.Geometry.LinearRing;else if("multipoint"==this.geometryType)b=OpenLayers.Geometry.MultiPoint;else if("point"!=this.geometryType&&"polygon"!=this.geometryType)return null;a=this.decodeDeltas(a,
2);for(var c=a.length,d=[],e=0;e+1<c;){var f=a[e++],g=a[e++];d.push(new OpenLayers.Geometry.Point(g,f))}return"point"==this.geometryType?new OpenLayers.Feature.Vector(d[0]):"polygon"==this.geometryType?new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(d)])):new OpenLayers.Feature.Vector(new b(d))},decode:function(a,b,c){a=this.decodeDeltas(a,b,c||1E5);c=a.length;for(var d=[],e=0;e+(b-1)<c;){for(var f=[],g=0;g<b;++g)f.push(a[e++]);d.push(f)}return d},
write:function(a){a=(a.constructor==Array?a[0]:a).geometry;var b=a.CLASS_NAME.split(".")[2].toLowerCase();if("point"==b)a=Array(a);else if("linestring"==b||"linearring"==b||"multipoint"==b)a=a.components;else if("polygon"==b)a=a.components[0].components;else return null;for(var b=[],c=a.length,d=0;d<c;++d){var e=a[d];b.push(e.y);b.push(e.x)}return this.encodeDeltas(b,2)},encode:function(a,b,c){c=c||1E5;for(var d=[],e=a.length,f=0;f<e;++f)for(var g=a[f],h=0;h<b;++h)d.push(g[h]);return this.encodeDeltas(d,
b,c)},encodeDeltas:function(a,b,c){var d,e=Array(b);for(d=0;d<b;++d)e[d]=0;for(var f=a.length,g=0;g<f;)for(d=0;d<b;++d,++g){var h=a[g],k=h-e[d];e[d]=h;a[g]=k}return this.encodeFloats(a,c||1E5)},decodeDeltas:function(a,b,c){var d,e=Array(b);for(d=0;d<b;++d)e[d]=0;a=this.decodeFloats(a,c||1E5);c=a.length;for(var f=0;f<c;)for(d=0;d<b;++d,++f)e[d]+=a[f],a[f]=e[d];return a},encodeFloats:function(a,b){for(var c=b||1E5,d=a.length,e=0;e<d;++e)a[e]=Math.round(a[e]*c);return this.encodeSignedIntegers(a)},decodeFloats:function(a,
b){for(var c=b||1E5,d=this.decodeSignedIntegers(a),e=d.length,f=0;f<e;++f)d[f]/=c;return d},encodeSignedIntegers:function(a){for(var b=a.length,c=0;c<b;++c){var d=a[c],e=d<<1;0>d&&(e=~e);a[c]=e}return this.encodeUnsignedIntegers(a)},decodeSignedIntegers:function(a){a=this.decodeUnsignedIntegers(a);for(var b=a.length,c=0;c<b;++c){var d=a[c];a[c]=d&1?~(d>>1):d>>1}return a},encodeUnsignedIntegers:function(a){for(var b="",c=a.length,d=0;d<c;++d)b+=this.encodeUnsignedInteger(a[d]);return b},decodeUnsignedIntegers:function(a){for(var b=
[],c=0,d=0,e=a.length,f=0;f<e;++f){var g=a.charCodeAt(f)-63,c=c|(g&31)<<d;32>g?(b.push(c),d=c=0):d+=5}return b},encodeFloat:function(a,b){a=Math.round(a*(b||1E5));return this.encodeSignedInteger(a)},decodeFloat:function(a,b){return this.decodeSignedInteger(a)/(b||1E5)},encodeSignedInteger:function(a){var b=a<<1;0>a&&(b=~b);return this.encodeUnsignedInteger(b)},decodeSignedInteger:function(a){a=this.decodeUnsignedInteger(a);return a&1?~(a>>1):a>>1},encodeUnsignedInteger:function(a){for(var b,c="";32<=
a;)b=(32|a&31)+63,c+=String.fromCharCode(b),a>>=5;return c+=String.fromCharCode(a+63)},decodeUnsignedInteger:function(a){for(var b=0,c=0,d=a.length,e=0;e<d;++e){var f=a.charCodeAt(e)-63,b=b|(f&31)<<c;if(32>f)break;c+=5}return b},CLASS_NAME:"OpenLayers.Format.EncodedPolyline"});OpenLayers.Control.Panel=OpenLayers.Class(OpenLayers.Control,{controls:null,autoActivate:!0,defaultControl:null,saveState:!1,allowDepress:!1,activeState:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.controls=[];this.activeState={}},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments);for(var a,b=this.controls.length-1;0<=b;b--)a=this.controls[b],a.events&&
a.events.un({activate:this.iconOn,deactivate:this.iconOff}),a.panel_div=null;this.activeState=null},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){for(var a,b=0,c=this.controls.length;b<c;b++)a=this.controls[b],(a===this.defaultControl||this.saveState&&this.activeState[a.id])&&a.activate();!0===this.saveState&&(this.defaultControl=null);this.redraw();return!0}return!1},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){for(var a,
b=0,c=this.controls.length;b<c;b++)a=this.controls[b],this.activeState[a.id]=a.deactivate();this.redraw();return!0}return!1},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.outsideViewport?(this.events.attachToElement(this.div),this.events.register("buttonclick",this,this.onButtonClick)):this.map.events.register("buttonclick",this,this.onButtonClick);this.addControlsToMap(this.controls);return this.div},redraw:function(){for(var a=this.div.childNodes.length-1;0<=a;a--)this.div.removeChild(this.div.childNodes[a]);
this.div.innerHTML="";if(this.active)for(var a=0,b=this.controls.length;a<b;a++)this.div.appendChild(this.controls[a].panel_div)},activateControl:function(a){if(!this.active)return!1;if(a.type==OpenLayers.Control.TYPE_BUTTON)a.trigger();else if(a.type==OpenLayers.Control.TYPE_TOGGLE)a.active?a.deactivate():a.activate();else if(this.allowDepress&&a.active)a.deactivate();else{for(var b,c=0,d=this.controls.length;c<d;c++)b=this.controls[c],b==a||b.type!==OpenLayers.Control.TYPE_TOOL&&null!=b.type||b.deactivate();
a.activate()}},addControls:function(a){OpenLayers.Util.isArray(a)||(a=[a]);this.controls=this.controls.concat(a);for(var b=0,c=a.length;b<c;b++){var d=a[b],e=this.createControlMarkup(d);OpenLayers.Element.addClass(e,d.displayClass+"ItemInactive");OpenLayers.Element.addClass(e,"olButton");""==d.title||e.title||(e.title=d.title);d.panel_div=e}this.map&&(this.addControlsToMap(a),this.redraw())},createControlMarkup:function(a){return document.createElement("div")},addControlsToMap:function(a){for(var b,
c=0,d=a.length;c<d;c++)b=a[c],!0===b.autoActivate?(b.autoActivate=!1,this.map.addControl(b),b.autoActivate=!0):(this.map.addControl(b),b.deactivate()),b.events.on({activate:this.iconOn,deactivate:this.iconOff})},iconOn:function(){var a=this.panel_div;a.className=a.className.replace(RegExp("\\b("+this.displayClass+"Item)Inactive\\b"),"$1Active")},iconOff:function(){var a=this.panel_div;a.className=a.className.replace(RegExp("\\b("+this.displayClass+"Item)Active\\b"),"$1Inactive")},onButtonClick:function(a){var b=
this.controls;a=a.buttonElement;for(var c=b.length-1;0<=c;--c)if(b[c].panel_div===a){this.activateControl(b[c]);break}},getControlsBy:function(a,b){var c="function"==typeof b.test;return OpenLayers.Array.filter(this.controls,function(d){return d[a]==b||c&&b.test(d[a])})},getControlsByName:function(a){return this.getControlsBy("name",a)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},CLASS_NAME:"OpenLayers.Control.Panel"});OpenLayers.Control.Button=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){},CLASS_NAME:"OpenLayers.Control.Button"});OpenLayers.Control.ZoomIn=OpenLayers.Class(OpenLayers.Control.Button,{trigger:function(){this.map&&this.map.zoomIn()},CLASS_NAME:"OpenLayers.Control.ZoomIn"});OpenLayers.Control.ZoomOut=OpenLayers.Class(OpenLayers.Control.Button,{trigger:function(){this.map&&this.map.zoomOut()},CLASS_NAME:"OpenLayers.Control.ZoomOut"});OpenLayers.Control.ZoomToMaxExtent=OpenLayers.Class(OpenLayers.Control.Button,{trigger:function(){this.map&&this.map.zoomToMaxExtent()},CLASS_NAME:"OpenLayers.Control.ZoomToMaxExtent"});OpenLayers.Control.ZoomPanel=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);this.addControls([new OpenLayers.Control.ZoomIn,new OpenLayers.Control.ZoomToMaxExtent,new OpenLayers.Control.ZoomOut])},CLASS_NAME:"OpenLayers.Control.ZoomPanel"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:!1,initialize:function(a,b,c,d){OpenLayers.Layer.prototype.initialize.apply(this,[a,d]);this.url=b;this.params||(this.params=OpenLayers.Util.extend({},c))},destroy:function(){this.params=this.url=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.getOptions()));
return a=OpenLayers.Layer.prototype.clone.apply(this,[a])},setUrl:function(a){this.url=a},mergeNewParams:function(a){this.params=OpenLayers.Util.extend(this.params,a);a=this.redraw();null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"params"});return a},redraw:function(a){return a?this.mergeNewParams({_olSalt:Math.random()}):OpenLayers.Layer.prototype.redraw.apply(this,[])},selectUrl:function(a,b){for(var c=1,d=0,e=a.length;d<e;d++)c*=a.charCodeAt(d)*this.URL_HASH_FACTOR,
c-=Math.floor(c);return b[Math.floor(c*b.length)]},getFullRequestString:function(a,b){var c=b||this.url,d=OpenLayers.Util.extend({},this.params),d=OpenLayers.Util.extend(d,a),e=OpenLayers.Util.getParameterString(d);OpenLayers.Util.isArray(c)&&(c=this.selectUrl(e,c));var e=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),f;for(f in d)f.toUpperCase()in e&&delete d[f];e=OpenLayers.Util.getParameterString(d);return OpenLayers.Util.urlAppend(c,e)},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Tile=OpenLayers.Class({events:null,eventListeners:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:!1,initialize:function(a,b,c,d,e,f){this.layer=a;this.position=b.clone();this.setBounds(c);this.url=d;e&&(this.size=e.clone());this.id=OpenLayers.Util.createUniqueID("Tile_");OpenLayers.Util.extend(this,f);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object)this.events.on(this.eventListeners)},unload:function(){this.isLoading&&(this.isLoading=
!1,this.events.triggerEvent("unload"))},destroy:function(){this.position=this.size=this.bounds=this.layer=null;this.eventListeners&&this.events.un(this.eventListeners);this.events.destroy();this.events=this.eventListeners=null},draw:function(a){a||this.clear();var b=this.shouldDraw();b&&(!a&&!1===this.events.triggerEvent("beforedraw"))&&(b=null);return b},shouldDraw:function(){var a=!1,b=this.layer.maxExtent;if(b){var c=this.layer.map,c=c.baseLayer.wrapDateLine&&c.getMaxExtent();this.bounds.intersectsBounds(b,
{inclusive:!1,worldBounds:c})&&(a=!0)}return a||this.layer.displayOutsideMaxExtent},setBounds:function(a){a=a.clone();if(this.layer.map.baseLayer.wrapDateLine){var b=this.layer.map.getMaxExtent(),c=this.layer.map.getResolution();a=a.wrapDateLine(b,{leftTolerance:c,rightTolerance:c})}this.bounds=a},moveTo:function(a,b,c){null==c&&(c=!0);this.setBounds(a);this.position=b.clone();c&&this.draw()},clear:function(a){},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,imageReloadAttempts:null,layerAlphaHack:null,asyncRequestId:null,maxGetUrlLength:null,canvasContext:null,crossOriginKeyword:null,initialize:function(a,b,c,d,e,f){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=d;this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();if(null!=this.maxGetUrlLength||this.layer.gutter||this.layerAlphaHack)this.frame=document.createElement("div"),this.frame.style.position=
"absolute",this.frame.style.overflow="hidden";null!=this.maxGetUrlLength&&OpenLayers.Util.extend(this,OpenLayers.Tile.Image.IFrame)},destroy:function(){this.imgDiv&&(this.clear(),this.frame=this.imgDiv=null);this.asyncRequestId=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments)},draw:function(){var a=OpenLayers.Tile.prototype.draw.apply(this,arguments);a?(this.layer!=this.layer.map.baseLayer&&this.layer.reproject&&(this.bounds=this.getBoundsFromBaseLayer(this.position)),this.isLoading?this._loadEvent=
"reload":(this.isLoading=!0,this._loadEvent="loadstart"),this.renderTile(),this.positionTile()):!1===a&&this.unload();return a},renderTile:function(){if(this.layer.async){var a=this.asyncRequestId=(this.asyncRequestId||0)+1;this.layer.getURLasync(this.bounds,function(b){a==this.asyncRequestId&&(this.url=b,this.initImage())},this)}else this.url=this.layer.getURL(this.bounds),this.initImage()},positionTile:function(){var a=this.getTile().style,b=this.frame?this.size:this.layer.getImageSize(this.bounds),
c=1;this.layer instanceof OpenLayers.Layer.Grid&&(c=this.layer.getServerResolution()/this.layer.map.getResolution());a.left=this.position.x+"px";a.top=this.position.y+"px";a.width=Math.round(c*b.w)+"px";a.height=Math.round(c*b.h)+"px"},clear:function(){OpenLayers.Tile.prototype.clear.apply(this,arguments);var a=this.imgDiv;if(a){var b=this.getTile();b.parentNode===this.layer.div&&this.layer.div.removeChild(b);this.setImgSrc();!0===this.layerAlphaHack&&(a.style.filter="");OpenLayers.Element.removeClass(a,
"olImageLoadError")}this.canvasContext=null},getImage:function(){if(!this.imgDiv){this.imgDiv=OpenLayers.Tile.Image.IMAGE.cloneNode(!1);var a=this.imgDiv.style;if(this.frame){var b=0,c=0;this.layer.gutter&&(b=100*(this.layer.gutter/this.layer.tileSize.w),c=100*(this.layer.gutter/this.layer.tileSize.h));a.left=-b+"%";a.top=-c+"%";a.width=2*b+100+"%";a.height=2*c+100+"%"}a.visibility="hidden";a.opacity=0;1>this.layer.opacity&&(a.filter="alpha(opacity="+100*this.layer.opacity+")");a.position="absolute";
this.layerAlphaHack&&(a.paddingTop=a.height,a.height="0",a.width="100%");this.frame&&this.frame.appendChild(this.imgDiv)}return this.imgDiv},setImage:function(a){this.imgDiv=a},initImage:function(){this.events.triggerEvent("beforeload");this.layer.div.appendChild(this.getTile());this.events.triggerEvent(this._loadEvent);var a=this.getImage();this.url&&OpenLayers.Util.isEquivalentUrl(a.src,this.url)?this._loadTimeout=window.setTimeout(OpenLayers.Function.bind(this.onImageLoad,this),0):(this.stopLoading(),
this.crossOriginKeyword&&a.removeAttribute("crossorigin"),OpenLayers.Event.observe(a,"load",OpenLayers.Function.bind(this.onImageLoad,this)),OpenLayers.Event.observe(a,"error",OpenLayers.Function.bind(this.onImageError,this)),this.imageReloadAttempts=0,this.setImgSrc(this.url))},setImgSrc:function(a){var b=this.imgDiv;a?(b.style.visibility="hidden",b.style.opacity=0,this.crossOriginKeyword&&("data:"!==a.substr(0,5)?b.setAttribute("crossorigin",this.crossOriginKeyword):b.removeAttribute("crossorigin")),
b.src=a):(this.stopLoading(),this.imgDiv=null,b.parentNode&&b.parentNode.removeChild(b))},getTile:function(){return this.frame?this.frame:this.getImage()},createBackBuffer:function(){if(this.imgDiv&&!this.isLoading){var a;this.frame?(a=this.frame.cloneNode(!1),a.appendChild(this.imgDiv)):a=this.imgDiv;this.imgDiv=null;return a}},onImageLoad:function(){var a=this.imgDiv;this.stopLoading();a.style.visibility="inherit";a.style.opacity=this.layer.opacity;this.isLoading=!1;this.canvasContext=null;this.events.triggerEvent("loadend");
!0===this.layerAlphaHack&&(a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+a.src+"', sizingMethod='scale')")},onImageError:function(){var a=this.imgDiv;null!=a.src&&(this.imageReloadAttempts++,this.imageReloadAttempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS?this.setImgSrc(this.layer.getURL(this.bounds)):(OpenLayers.Element.addClass(a,"olImageLoadError"),this.events.triggerEvent("loaderror"),this.onImageLoad()))},stopLoading:function(){OpenLayers.Event.stopObservingElement(this.imgDiv);
window.clearTimeout(this._loadTimeout);delete this._loadTimeout},getCanvasContext:function(){if(OpenLayers.CANVAS_SUPPORTED&&this.imgDiv&&!this.isLoading){if(!this.canvasContext){var a=document.createElement("canvas");a.width=this.size.w;a.height=this.size.h;this.canvasContext=a.getContext("2d");this.canvasContext.drawImage(this.imgDiv,0,0)}return this.canvasContext}},CLASS_NAME:"OpenLayers.Tile.Image"});
OpenLayers.Tile.Image.IMAGE=function(){var a=new Image;a.className="olTileImage";a.galleryImg="no";return a}();OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,tileOriginCorner:"bl",tileOrigin:null,tileOptions:null,tileClass:OpenLayers.Tile.Image,grid:null,singleTile:!1,ratio:1.5,buffer:0,transitionEffect:"resize",numLoadingTiles:0,serverResolutions:null,loading:!1,backBuffer:null,gridResolution:null,backBufferResolution:null,backBufferLonLat:null,backBufferTimerId:null,removeBackBufferDelay:null,className:null,gridLayout:null,rowSign:null,transitionendEvents:["transitionend",
"webkitTransitionEnd","otransitionend","oTransitionEnd"],initialize:function(a,b,c,d){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.grid=[];this._removeBackBuffer=OpenLayers.Function.bind(this.removeBackBuffer,this);this.initProperties();this.rowSign="t"===this.tileOriginCorner.substr(0,1)?1:-1},initProperties:function(){void 0===this.options.removeBackBufferDelay&&(this.removeBackBufferDelay=this.singleTile?0:2500);void 0===this.options.className&&(this.className=this.singleTile?
"olLayerGridSingleTile":"olLayerGrid")},setMap:function(a){OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this,a);OpenLayers.Element.addClass(this.div,this.className)},removeMap:function(a){this.removeBackBuffer()},destroy:function(){this.removeBackBuffer();this.clearGrid();this.tileSize=this.grid=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments)},clearGrid:function(){if(this.grid){for(var a=0,b=this.grid.length;a<b;a++)for(var c=this.grid[a],d=0,e=c.length;d<e;d++)this.destroyTile(c[d]);
this.grid=[];this.gridLayout=this.gridResolution=null}},addOptions:function(a,b){var c=void 0!==a.singleTile&&a.singleTile!==this.singleTile;OpenLayers.Layer.HTTPRequest.prototype.addOptions.apply(this,arguments);this.map&&c&&(this.initProperties(),this.clearGrid(),this.tileSize=this.options.tileSize,this.setTileSize(),this.moveTo(null,!0))},clone:function(a){null==a&&(a=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.getOptions()));a=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,
[a]);null!=this.tileSize&&(a.tileSize=this.tileSize.clone());a.grid=[];a.gridResolution=null;a.backBuffer=null;a.backBufferTimerId=null;a.loading=!1;a.numLoadingTiles=0;return a},moveTo:function(a,b,c){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);a=a||this.map.getExtent();if(null!=a){var d=!this.grid.length||b,e=this.getTilesBounds(),f=this.map.getResolution();this.getServerResolution(f);if(this.singleTile){if(d||!c&&!e.containsBounds(a))b&&"resize"!==this.transitionEffect&&
this.removeBackBuffer(),b&&"resize"!==this.transitionEffect||this.applyBackBuffer(f),this.initSingleTile(a)}else(d=d||!e.intersectsBounds(a,{worldBounds:this.map.baseLayer.wrapDateLine&&this.map.getMaxExtent()}))?(!b||"resize"!==this.transitionEffect&&this.gridResolution!==f||this.applyBackBuffer(f),this.initGriddedTiles(a)):this.moveGriddedTiles()}},getTileData:function(a){var b=null,c=a.lon,d=a.lat,e=this.grid.length;if(this.map&&e){var f=this.map.getResolution();a=this.tileSize.w;var g=this.tileSize.h,
h=this.grid[0][0].bounds,k=h.left,h=h.top;if(c<k&&this.map.baseLayer.wrapDateLine)var l=this.map.getMaxExtent().getWidth(),m=Math.ceil((k-c)/l),c=c+l*m;c=(c-k)/(f*a);d=(h-d)/(f*g);f=Math.floor(c);k=Math.floor(d);0<=k&&k<e&&(e=this.grid[k][f])&&(b={tile:e,i:Math.floor((c-f)*a),j:Math.floor((d-k)*g)})}return b},destroyTile:function(a){this.removeTileMonitoringHooks(a);a.destroy()},getServerResolution:function(a){var b=Number.POSITIVE_INFINITY;a=a||this.map.getResolution();if(this.serverResolutions&&
-1===OpenLayers.Util.indexOf(this.serverResolutions,a)){var c,d,e,f;for(c=this.serverResolutions.length-1;0<=c;c--){e=this.serverResolutions[c];d=Math.abs(e-a);if(d>b)break;b=d;f=e}a=f}return a},getServerZoom:function(){var a=this.getServerResolution();return this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,a):this.map.getZoomForResolution(a)+(this.zoomOffset||0)},applyBackBuffer:function(a){null!==this.backBufferTimerId&&this.removeBackBuffer();var b=this.backBuffer;if(!b){b=
this.createBackBuffer();if(!b)return;a===this.gridResolution?this.div.insertBefore(b,this.div.firstChild):this.map.baseLayer.div.parentNode.insertBefore(b,this.map.baseLayer.div);this.backBuffer=b;var c=this.grid[0][0].bounds;this.backBufferLonLat={lon:c.left,lat:c.top};this.backBufferResolution=this.gridResolution}for(var c=this.backBufferResolution/a,d=b.childNodes,e,f=d.length-1;0<=f;--f)e=d[f],e.style.top=(c*e._i*e._h|0)+"px",e.style.left=(c*e._j*e._w|0)+"px",e.style.width=Math.round(c*e._w)+
"px",e.style.height=Math.round(c*e._h)+"px";a=this.getViewPortPxFromLonLat(this.backBufferLonLat,a);c=this.map.layerContainerOriginPx.y;b.style.left=Math.round(a.x-this.map.layerContainerOriginPx.x)+"px";b.style.top=Math.round(a.y-c)+"px"},createBackBuffer:function(){var a;if(0<this.grid.length){a=document.createElement("div");a.id=this.div.id+"_bb";a.className="olBackBuffer";a.style.position="absolute";var b=this.map;a.style.zIndex="resize"===this.transitionEffect?this.getZIndex()-1:b.Z_INDEX_BASE.BaseLayer-
(b.getNumLayers()-b.getLayerIndex(this));for(var b=0,c=this.grid.length;b<c;b++)for(var d=0,e=this.grid[b].length;d<e;d++){var f=this.grid[b][d],g=this.grid[b][d].createBackBuffer();g&&(g._i=b,g._j=d,g._w=f.size.w,g._h=f.size.h,g.id=f.id+"_bb",a.appendChild(g))}}return a},removeBackBuffer:function(){if(this._transitionElement){for(var a=this.transitionendEvents.length-1;0<=a;--a)OpenLayers.Event.stopObserving(this._transitionElement,this.transitionendEvents[a],this._removeBackBuffer);delete this._transitionElement}this.backBuffer&&
(this.backBuffer.parentNode&&this.backBuffer.parentNode.removeChild(this.backBuffer),this.backBufferResolution=this.backBuffer=null,null!==this.backBufferTimerId&&(window.clearTimeout(this.backBufferTimerId),this.backBufferTimerId=null))},moveByPx:function(a,b){this.singleTile||this.moveGriddedTiles()},setTileSize:function(a){this.singleTile&&(a=this.map.getSize(),a.h=parseInt(a.h*this.ratio,10),a.w=parseInt(a.w*this.ratio,10));OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[a])},getTilesBounds:function(){var a=
null,b=this.grid.length;if(b)var a=this.grid[b-1][0].bounds,b=this.grid[0].length*a.getWidth(),c=this.grid.length*a.getHeight(),a=new OpenLayers.Bounds(a.left,a.bottom,a.left+b,a.bottom+c);return a},initSingleTile:function(a){this.events.triggerEvent("retile");var b=a.getCenterLonLat(),c=a.getWidth()*this.ratio;a=a.getHeight()*this.ratio;b=new OpenLayers.Bounds(b.lon-c/2,b.lat-a/2,b.lon+c/2,b.lat+a/2);c=this.map.getLayerPxFromLonLat({lon:b.left,lat:b.top});this.grid.length||(this.grid[0]=[]);(a=this.grid[0][0])?
a.moveTo(b,c):(a=this.addTile(b,c),this.addTileMonitoringHooks(a),a.draw(),this.grid[0][0]=a);this.removeExcessTiles(1,1);this.gridResolution=this.getServerResolution()},calculateGridLayout:function(a,b,c){var d=c*this.tileSize.w;c*=this.tileSize.h;var e=Math.floor((a.left-b.lon)/d)-this.buffer,f=this.rowSign;a=Math[~f?"floor":"ceil"](f*(b.lat-a.top+c)/c)-this.buffer*f;return{tilelon:d,tilelat:c,startcol:e,startrow:a}},getTileOrigin:function(){var a=this.tileOrigin;if(!a)var a=this.getMaxExtent(),
b={tl:["left","top"],tr:["right","top"],bl:["left","bottom"],br:["right","bottom"]}[this.tileOriginCorner],a=new OpenLayers.LonLat(a[b[0]],a[b[1]]);return a},getTileBoundsForGridIndex:function(a,b){var c=this.getTileOrigin(),d=this.gridLayout,e=d.tilelon,f=d.tilelat,g=d.startcol,d=d.startrow,h=this.rowSign;return new OpenLayers.Bounds(c.lon+(g+b)*e,c.lat-(d+a*h)*f*h,c.lon+(g+b+1)*e,c.lat-(d+(a-1)*h)*f*h)},initGriddedTiles:function(a){this.events.triggerEvent("retile");var b=this.map.getSize(),c=this.getTileOrigin(),
d=this.map.getResolution(),e=this.getServerResolution(),f=d/e,d=this.tileSize.w/f,f=this.tileSize.h/f,g=Math.ceil(b.h/f)+2*this.buffer+1,b=Math.ceil(b.w/d)+2*this.buffer+1;this.gridLayout=e=this.calculateGridLayout(a,c,e);var c=e.tilelon,h=e.tilelat,e=this.map.layerContainerOriginPx.x,k=this.map.layerContainerOriginPx.y,l=this.getTileBoundsForGridIndex(0,0),m=this.map.getViewPortPxFromLonLat(new OpenLayers.LonLat(l.left,l.top));m.x=Math.round(m.x)-e;m.y=Math.round(m.y)-k;var e=[],k=this.map.getCenter(),
n=0;do{var p=this.grid[n];p||(p=[],this.grid.push(p));var q=0;do{var l=this.getTileBoundsForGridIndex(n,q),r=m.clone();r.x+=q*Math.round(d);r.y+=n*Math.round(f);var s=p[q];s?s.moveTo(l,r,!1):(s=this.addTile(l,r),this.addTileMonitoringHooks(s),p.push(s));r=l.getCenterLonLat();e.push({tile:s,distance:Math.pow(r.lon-k.lon,2)+Math.pow(r.lat-k.lat,2)});q+=1}while(l.right<=a.right+c*this.buffer||q<b);n+=1}while(l.bottom>=a.bottom-h*this.buffer||n<g);this.removeExcessTiles(n,q);this.gridResolution=d=this.getServerResolution();
e.sort(function(a,b){return a.distance-b.distance});a=0;for(d=e.length;a<d;++a)e[a].tile.draw()},getMaxExtent:function(){return this.maxExtent},addTile:function(a,b){var c=new this.tileClass(this,b,a,null,this.tileSize,this.tileOptions);this.events.triggerEvent("addtile",{tile:c});return c},addTileMonitoringHooks:function(a){a.onLoadStart=function(){!1===this.loading&&(this.loading=!0,this.events.triggerEvent("loadstart"));this.events.triggerEvent("tileloadstart",{tile:a});this.numLoadingTiles++;
!this.singleTile&&(this.backBuffer&&this.gridResolution===this.backBufferResolution)&&OpenLayers.Element.addClass(a.getTile(),"olTileReplacing")};a.onLoadEnd=function(b){this.numLoadingTiles--;b="unload"===b.type;this.events.triggerEvent("tileloaded",{tile:a,aborted:b});if(!this.singleTile&&!b&&this.backBuffer&&this.gridResolution===this.backBufferResolution){var c=a.getTile();if("none"===OpenLayers.Element.getStyle(c,"display")){var d=document.getElementById(a.id+"_bb");d&&d.parentNode.removeChild(d)}OpenLayers.Element.removeClass(c,
"olTileReplacing")}if(0===this.numLoadingTiles){if(this.backBuffer)if(0===this.backBuffer.childNodes.length)this.removeBackBuffer();else{this._transitionElement=b?this.div.lastChild:a.imgDiv;b=this.transitionendEvents;for(c=b.length-1;0<=c;--c)OpenLayers.Event.observe(this._transitionElement,b[c],this._removeBackBuffer);this.backBufferTimerId=window.setTimeout(this._removeBackBuffer,this.removeBackBufferDelay)}this.loading=!1;this.events.triggerEvent("loadend")}};a.onLoadError=function(){this.events.triggerEvent("tileerror",
{tile:a})};a.events.on({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,loaderror:a.onLoadError,scope:this})},removeTileMonitoringHooks:function(a){a.unload();a.events.un({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,loaderror:a.onLoadError,scope:this})},moveGriddedTiles:function(){for(var a=this.buffer+1;;){var b=this.grid[0][0],c=b.position.x+this.map.layerContainerOriginPx.x,b=b.position.y+this.map.layerContainerOriginPx.y,d=this.getServerResolution()/this.map.getResolution(),
d={w:Math.round(this.tileSize.w*d),h:Math.round(this.tileSize.h*d)};if(c>-d.w*(a-1))this.shiftColumn(!0,d);else if(c<-d.w*a)this.shiftColumn(!1,d);else if(b>-d.h*(a-1))this.shiftRow(!0,d);else if(b<-d.h*a)this.shiftRow(!1,d);else break}},shiftRow:function(a,b){var c=this.grid,d=a?0:c.length-1,e=a?-1:1;this.gridLayout.startrow+=e*this.rowSign;for(var f=c[d],g=c[a?"pop":"shift"](),h=0,k=g.length;h<k;h++){var l=g[h],m=f[h].position.clone();m.y+=b.h*e;l.moveTo(this.getTileBoundsForGridIndex(d,h),m)}c[a?
"unshift":"push"](g)},shiftColumn:function(a,b){var c=this.grid,d=a?0:c[0].length-1,e=a?-1:1;this.gridLayout.startcol+=e;for(var f=0,g=c.length;f<g;f++){var h=c[f],k=h[d].position.clone(),l=h[a?"pop":"shift"]();k.x+=b.w*e;l.moveTo(this.getTileBoundsForGridIndex(f,d),k);h[a?"unshift":"push"](l)}},removeExcessTiles:function(a,b){for(var c,d;this.grid.length>a;){var e=this.grid.pop();c=0;for(d=e.length;c<d;c++){var f=e[c];this.destroyTile(f)}}c=0;for(d=this.grid.length;c<d;c++)for(;this.grid[c].length>
b;)e=this.grid[c],f=e.pop(),this.destroyTile(f)},onMapResize:function(){this.singleTile&&(this.clearGrid(),this.setTileSize())},getTileBounds:function(a){var b=this.maxExtent,c=this.getResolution(),d=c*this.tileSize.w,c=c*this.tileSize.h,e=this.getLonLatFromViewPortPx(a);a=b.left+d*Math.floor((e.lon-b.left)/d);b=b.bottom+c*Math.floor((e.lat-b.bottom)/c);return new OpenLayers.Bounds(a,b,a+d,b+c)},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Format.ArcXML=OpenLayers.Class(OpenLayers.Format.XML,{fontStyleKeys:"antialiasing blockout font fontcolor fontsize fontstyle glowing interval outline printmode shadow transparency".split(" "),request:null,response:null,initialize:function(a){this.request=new OpenLayers.Format.ArcXML.Request;this.response=new OpenLayers.Format.ArcXML.Response;if(a)if("feature"==a.requesttype){this.request.get_image=null;var b=this.request.get_feature.query;this.addCoordSys(b.featurecoordsys,a.featureCoordSys);
this.addCoordSys(b.filtercoordsys,a.filterCoordSys);a.polygon?(b.isspatial=!0,b.spatialfilter.polygon=a.polygon):a.envelope&&(b.isspatial=!0,b.spatialfilter.envelope={minx:0,miny:0,maxx:0,maxy:0},this.parseEnvelope(b.spatialfilter.envelope,a.envelope))}else"image"==a.requesttype?(this.request.get_feature=null,b=this.request.get_image.properties,this.parseEnvelope(b.envelope,a.envelope),this.addLayers(b.layerlist,a.layers),this.addImageSize(b.imagesize,a.tileSize),this.addCoordSys(b.featurecoordsys,
a.featureCoordSys),this.addCoordSys(b.filtercoordsys,a.filterCoordSys)):this.request=null;OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},parseEnvelope:function(a,b){b&&4==b.length&&(a.minx=b[0],a.miny=b[1],a.maxx=b[2],a.maxy=b[3])},addLayers:function(a,b){for(var c=0,d=b.length;c<d;c++)a.push(b[c])},addImageSize:function(a,b){null!==b&&(a.width=b.w,a.height=b.h,a.printwidth=b.w,a.printheight=b.h)},addCoordSys:function(a,b){"string"==typeof b?(a.id=parseInt(b),a.string=b):"object"==typeof b&&
null!==b.proj&&(a.id=b.proj.srsProjNumber,a.string=b.proj.srsCode)},iserror:function(a){var b=null;a?(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]),a=a.documentElement.getElementsByTagName("ERROR"),b=null!==a&&0<a.length):b=""!==this.response.error;return b},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=null;a&&a.documentElement&&(b="ARCXML"==a.documentElement.nodeName?a.documentElement:a.documentElement.getElementsByTagName("ARCXML")[0]);
if(!b||"parsererror"===b.firstChild.nodeName){var c,d;try{c=a.firstChild.nodeValue,d=a.firstChild.childNodes[1].firstChild.nodeValue}catch(e){}throw{message:"Error parsing the ArcXML request",error:c,source:d};}return this.parseResponse(b)},write:function(a){a||(a=this.request);var b=this.createElementNS("","ARCXML");b.setAttribute("version","1.1");var c=this.createElementNS("","REQUEST");if(null!=a.get_image){var d=this.createElementNS("","GET_IMAGE");c.appendChild(d);var e=this.createElementNS("",
"PROPERTIES");d.appendChild(e);a=a.get_image.properties;null!=a.featurecoordsys&&(d=this.createElementNS("","FEATURECOORDSYS"),e.appendChild(d),0===a.featurecoordsys.id?d.setAttribute("string",a.featurecoordsys.string):d.setAttribute("id",a.featurecoordsys.id));null!=a.filtercoordsys&&(d=this.createElementNS("","FILTERCOORDSYS"),e.appendChild(d),0===a.filtercoordsys.id?d.setAttribute("string",a.filtercoordsys.string):d.setAttribute("id",a.filtercoordsys.id));null!=a.envelope&&(d=this.createElementNS("",
"ENVELOPE"),e.appendChild(d),d.setAttribute("minx",a.envelope.minx),d.setAttribute("miny",a.envelope.miny),d.setAttribute("maxx",a.envelope.maxx),d.setAttribute("maxy",a.envelope.maxy));d=this.createElementNS("","IMAGESIZE");e.appendChild(d);d.setAttribute("height",a.imagesize.height);d.setAttribute("width",a.imagesize.width);if(a.imagesize.height!=a.imagesize.printheight||a.imagesize.width!=a.imagesize.printwidth)d.setAttribute("printheight",a.imagesize.printheight),d.setArrtibute("printwidth",a.imagesize.printwidth);
null!=a.background&&(d=this.createElementNS("","BACKGROUND"),e.appendChild(d),d.setAttribute("color",a.background.color.r+","+a.background.color.g+","+a.background.color.b),null!==a.background.transcolor&&d.setAttribute("transcolor",a.background.transcolor.r+","+a.background.transcolor.g+","+a.background.transcolor.b));if(null!=a.layerlist&&0<a.layerlist.length)for(d=this.createElementNS("","LAYERLIST"),e.appendChild(d),e=0;e<a.layerlist.length;e++){var f=this.createElementNS("","LAYERDEF");d.appendChild(f);
f.setAttribute("id",a.layerlist[e].id);f.setAttribute("visible",a.layerlist[e].visible);if("object"==typeof a.layerlist[e].query){var g=a.layerlist[e].query;if(0>g.where.length)continue;var h=null,h="boolean"==typeof g.spatialfilter&&g.spatialfilter?this.createElementNS("","SPATIALQUERY"):this.createElementNS("","QUERY");h.setAttribute("where",g.where);"number"==typeof g.accuracy&&0<g.accuracy&&h.setAttribute("accuracy",g.accuracy);"number"==typeof g.featurelimit&&2E3>g.featurelimit&&h.setAttribute("featurelimit",
g.featurelimit);"string"==typeof g.subfields&&"#ALL#"!=g.subfields&&h.setAttribute("subfields",g.subfields);"string"==typeof g.joinexpression&&0<g.joinexpression.length&&h.setAttribute("joinexpression",g.joinexpression);"string"==typeof g.jointables&&0<g.jointables.length&&h.setAttribute("jointables",g.jointables);f.appendChild(h)}"object"==typeof a.layerlist[e].renderer&&this.addRenderer(f,a.layerlist[e].renderer)}}else null!=a.get_feature&&(d=this.createElementNS("","GET_FEATURES"),d.setAttribute("outputmode",
"newxml"),d.setAttribute("checkesc","true"),a.get_feature.geometry?d.setAttribute("geometry",a.get_feature.geometry):d.setAttribute("geometry","false"),a.get_feature.compact&&d.setAttribute("compact",a.get_feature.compact),"number"==a.get_feature.featurelimit&&d.setAttribute("featurelimit",a.get_feature.featurelimit),d.setAttribute("globalenvelope","true"),c.appendChild(d),null!=a.get_feature.layer&&0<a.get_feature.layer.length&&(e=this.createElementNS("","LAYER"),e.setAttribute("id",a.get_feature.layer),
d.appendChild(e)),a=a.get_feature.query,null!=a&&(e=null,e=a.isspatial?this.createElementNS("","SPATIALQUERY"):this.createElementNS("","QUERY"),d.appendChild(e),"number"==typeof a.accuracy&&e.setAttribute("accuracy",a.accuracy),null!=a.featurecoordsys&&(d=this.createElementNS("","FEATURECOORDSYS"),0==a.featurecoordsys.id?d.setAttribute("string",a.featurecoordsys.string):d.setAttribute("id",a.featurecoordsys.id),e.appendChild(d)),null!=a.filtercoordsys&&(d=this.createElementNS("","FILTERCOORDSYS"),
0===a.filtercoordsys.id?d.setAttribute("string",a.filtercoordsys.string):d.setAttribute("id",a.filtercoordsys.id),e.appendChild(d)),0<a.buffer&&(d=this.createElementNS("","BUFFER"),d.setAttribute("distance",a.buffer),e.appendChild(d)),a.isspatial&&(d=this.createElementNS("","SPATIALFILTER"),d.setAttribute("relation",a.spatialfilter.relation),e.appendChild(d),a.spatialfilter.envelope?(f=this.createElementNS("","ENVELOPE"),f.setAttribute("minx",a.spatialfilter.envelope.minx),f.setAttribute("miny",a.spatialfilter.envelope.miny),
f.setAttribute("maxx",a.spatialfilter.envelope.maxx),f.setAttribute("maxy",a.spatialfilter.envelope.maxy),d.appendChild(f)):"object"==typeof a.spatialfilter.polygon&&d.appendChild(this.writePolygonGeometry(a.spatialfilter.polygon))),null!=a.where&&0<a.where.length&&e.setAttribute("where",a.where)));b.appendChild(c);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},addGroupRenderer:function(a,b){var c=this.createElementNS("","GROUPRENDERER");a.appendChild(c);for(var d=0;d<b.length;d++)this.addRenderer(c,
b[d])},addRenderer:function(a,b){if(OpenLayers.Util.isArray(b))this.addGroupRenderer(a,b);else{var c=this.createElementNS("",b.type.toUpperCase()+"RENDERER");a.appendChild(c);"VALUEMAPRENDERER"==c.tagName?this.addValueMapRenderer(c,b):"VALUEMAPLABELRENDERER"==c.tagName?this.addValueMapLabelRenderer(c,b):"SIMPLELABELRENDERER"==c.tagName?this.addSimpleLabelRenderer(c,b):"SCALEDEPENDENTRENDERER"==c.tagName&&this.addScaleDependentRenderer(c,b)}},addScaleDependentRenderer:function(a,b){"string"!=typeof b.lower&&
"number"!=typeof b.lower||a.setAttribute("lower",b.lower);"string"!=typeof b.upper&&"number"!=typeof b.upper||a.setAttribute("upper",b.upper);this.addRenderer(a,b.renderer)},addValueMapLabelRenderer:function(a,b){a.setAttribute("lookupfield",b.lookupfield);a.setAttribute("labelfield",b.labelfield);if("object"==typeof b.exacts)for(var c=0,d=b.exacts.length;c<d;c++){var e=b.exacts[c],f=this.createElementNS("","EXACT");"string"==typeof e.value&&f.setAttribute("value",e.value);"string"==typeof e.label&&
f.setAttribute("label",e.label);"string"==typeof e.method&&f.setAttribute("method",e.method);a.appendChild(f);if("object"==typeof e.symbol){var g=null;"text"==e.symbol.type&&(g=this.createElementNS("","TEXTSYMBOL"));if(null!=g){for(var h=this.fontStyleKeys,k=0,l=h.length;k<l;k++){var m=h[k];e.symbol[m]&&g.setAttribute(m,e.symbol[m])}f.appendChild(g)}}}},addValueMapRenderer:function(a,b){a.setAttribute("lookupfield",b.lookupfield);if("object"==typeof b.ranges)for(var c=0,d=b.ranges.length;c<d;c++){var e=
b.ranges[c],f=this.createElementNS("","RANGE");f.setAttribute("lower",e.lower);f.setAttribute("upper",e.upper);a.appendChild(f);if("object"==typeof e.symbol){var g=null;"simplepolygon"==e.symbol.type&&(g=this.createElementNS("","SIMPLEPOLYGONSYMBOL"));null!=g&&("string"==typeof e.symbol.boundarycolor&&g.setAttribute("boundarycolor",e.symbol.boundarycolor),"string"==typeof e.symbol.fillcolor&&g.setAttribute("fillcolor",e.symbol.fillcolor),"number"==typeof e.symbol.filltransparency&&g.setAttribute("filltransparency",
e.symbol.filltransparency),f.appendChild(g))}}else if("object"==typeof b.exacts)for(c=0,d=b.exacts.length;c<d;c++)e=b.exacts[c],f=this.createElementNS("","EXACT"),"string"==typeof e.value&&f.setAttribute("value",e.value),"string"==typeof e.label&&f.setAttribute("label",e.label),"string"==typeof e.method&&f.setAttribute("method",e.method),a.appendChild(f),"object"==typeof e.symbol&&(g=null,"simplemarker"==e.symbol.type&&(g=this.createElementNS("","SIMPLEMARKERSYMBOL")),null!=g&&("string"==typeof e.symbol.antialiasing&&
g.setAttribute("antialiasing",e.symbol.antialiasing),"string"==typeof e.symbol.color&&g.setAttribute("color",e.symbol.color),"string"==typeof e.symbol.outline&&g.setAttribute("outline",e.symbol.outline),"string"==typeof e.symbol.overlap&&g.setAttribute("overlap",e.symbol.overlap),"string"==typeof e.symbol.shadow&&g.setAttribute("shadow",e.symbol.shadow),"number"==typeof e.symbol.transparency&&g.setAttribute("transparency",e.symbol.transparency),"string"==typeof e.symbol.usecentroid&&g.setAttribute("usecentroid",
e.symbol.usecentroid),"number"==typeof e.symbol.width&&g.setAttribute("width",e.symbol.width),f.appendChild(g)))},addSimpleLabelRenderer:function(a,b){a.setAttribute("field",b.field);for(var c="featureweight howmanylabels labelbufferratio labelpriorities labelweight linelabelposition rotationalangles".split(" "),d=0,e=c.length;d<e;d++){var f=c[d];b[f]&&a.setAttribute(f,b[f])}if("text"==b.symbol.type){var g=b.symbol,h=this.createElementNS("","TEXTSYMBOL");a.appendChild(h);c=this.fontStyleKeys;d=0;
for(e=c.length;d<e;d++)f=c[d],g[f]&&h.setAttribute(f,b[f])}},writePolygonGeometry:function(a){if(!(a instanceof OpenLayers.Geometry.Polygon))throw{message:"Cannot write polygon geometry to ArcXML with an "+a.CLASS_NAME+" object.",geometry:a};for(var b=this.createElementNS("","POLYGON"),c=0,d=a.components.length;c<d;c++){for(var e=a.components[c],f=this.createElementNS("","RING"),g=0,h=e.components.length;g<h;g++){var k=e.components[g],l=this.createElementNS("","POINT");l.setAttribute("x",k.x);l.setAttribute("y",
k.y);f.appendChild(l)}b.appendChild(f)}return b},parseResponse:function(a){"string"==typeof a&&(a=(new OpenLayers.Format.XML).read(a));var b=new OpenLayers.Format.ArcXML.Response,c=a.getElementsByTagName("ERROR");if(null!=c&&0<c.length)b.error=this.getChildValue(c,"Unknown error.");else{c=a.getElementsByTagName("RESPONSE");if(null==c||0==c.length)return b.error="No RESPONSE tag found in ArcXML response.",b;var d=c[0].firstChild.nodeName;"#text"==d&&(d=c[0].firstChild.nextSibling.nodeName);if("IMAGE"==
d)c=a.getElementsByTagName("ENVELOPE"),a=a.getElementsByTagName("OUTPUT"),null==c||0==c.length?b.error="No ENVELOPE tag found in ArcXML response.":null==a||0==a.length?b.error="No OUTPUT tag found in ArcXML response.":(c=this.parseAttributes(c[0]),d=this.parseAttributes(a[0]),b.image="string"==typeof d.type?{envelope:c,output:{type:d.type,data:this.getChildValue(a[0])}}:{envelope:c,output:d});else if("FEATURES"==d){if(a=c[0].getElementsByTagName("FEATURES"),c=a[0].getElementsByTagName("FEATURECOUNT"),
b.features.featurecount=c[0].getAttribute("count"),0<b.features.featurecount)for(c=a[0].getElementsByTagName("ENVELOPE"),b.features.envelope=this.parseAttributes(c[0],"number"),a=a[0].getElementsByTagName("FEATURE"),c=0;c<a.length;c++){for(var d=new OpenLayers.Feature.Vector,e=a[c].getElementsByTagName("FIELD"),f=0;f<e.length;f++){var g=e[f].getAttribute("name"),h=e[f].getAttribute("value");d.attributes[g]=h}e=a[c].getElementsByTagName("POLYGON");if(0<e.length){e=e[0].getElementsByTagName("RING");
f=[];for(g=0;g<e.length;g++){h=[];h.push(this.parsePointGeometry(e[g]));for(var k=e[g].getElementsByTagName("HOLE"),l=0;l<k.length;l++)h.push(this.parsePointGeometry(k[l]));f.push(new OpenLayers.Geometry.Polygon(h))}d.geometry=1==f.length?f[0]:new OpenLayers.Geometry.MultiPolygon(f)}b.features.feature.push(d)}}else b.error="Unidentified response type."}return b},parseAttributes:function(a,b){for(var c={},d=0;d<a.attributes.length;d++)c[a.attributes[d].nodeName]="number"==b?parseFloat(a.attributes[d].nodeValue):
a.attributes[d].nodeValue;return c},parsePointGeometry:function(a){var b=[],c=a.getElementsByTagName("COORDS");if(0<c.length)for(a=this.getChildValue(c[0]),a=a.split(/;/),c=0;c<a.length;c++){var d=a[c].split(/ /);b.push(new OpenLayers.Geometry.Point(d[0],d[1]))}else if(a=a.getElementsByTagName("POINT"),0<a.length)for(c=0;c<a.length;c++)b.push(new OpenLayers.Geometry.Point(parseFloat(a[c].getAttribute("x")),parseFloat(a[c].getAttribute("y"))));return new OpenLayers.Geometry.LinearRing(b)},CLASS_NAME:"OpenLayers.Format.ArcXML"});
OpenLayers.Format.ArcXML.Request=OpenLayers.Class({initialize:function(a){return OpenLayers.Util.extend(this,{get_image:{properties:{background:null,draw:!0,envelope:{minx:0,miny:0,maxx:0,maxy:0},featurecoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},filtercoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},imagesize:{height:0,width:0,dpi:96,printheight:0,printwidth:0,scalesymbols:!1},layerlist:[],output:{baseurl:"",legendbaseurl:"",legendname:"",legendpath:"",
legendurl:"",name:"",path:"",type:"jpg",url:""}}},get_feature:{layer:"",query:{isspatial:!1,featurecoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},filtercoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},buffer:0,where:"",spatialfilter:{relation:"envelope_intersection",envelope:null}}},environment:{separators:{cs:" ",ts:";"}},layer:[],workspaces:[]})},CLASS_NAME:"OpenLayers.Format.ArcXML.Request"});
OpenLayers.Format.ArcXML.Response=OpenLayers.Class({initialize:function(a){return OpenLayers.Util.extend(this,{image:{envelope:null,output:""},features:{featurecount:0,envelope:null,feature:[]},error:""})},CLASS_NAME:"OpenLayers.Format.ArcXML.Response"});(function(){function a(){this._object=f&&!k?new f:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[]}function b(){return new a}function c(a){b.onreadystatechange&&b.onreadystatechange.apply(a);a.dispatchEvent({type:"readystatechange",bubbles:!1,cancelable:!1,timeStamp:new Date+0})}function d(a){try{a.responseText=a._object.responseText}catch(b){}try{var c;var d=a._object,e=d.responseXML,f=d.responseText;h&&(f&&e&&!e.documentElement&&d.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/))&&
(e=new window.ActiveXObject("Microsoft.XMLDOM"),e.async=!1,e.validateOnParse=!1,e.loadXML(f));c=e&&(h&&0!=e.parseError||!e.documentElement||e.documentElement&&"parsererror"==e.documentElement.tagName)?null:e;a.responseXML=c}catch(g){}try{a.status=a._object.status}catch(k){}try{a.statusText=a._object.statusText}catch(u){}}function e(a){a._object.onreadystatechange=new window.Function}var f=window.XMLHttpRequest,g=!!window.controllers,h=window.document.all&&!window.opera,k=h&&window.navigator.userAgent.match(/MSIE 7.0/);
b.prototype=a.prototype;g&&f.wrapped&&(b.wrapped=f.wrapped);b.UNSENT=0;b.OPENED=1;b.HEADERS_RECEIVED=2;b.LOADING=3;b.DONE=4;b.prototype.readyState=b.UNSENT;b.prototype.responseText="";b.prototype.responseXML=null;b.prototype.status=0;b.prototype.statusText="";b.prototype.priority="NORMAL";b.prototype.onreadystatechange=null;b.onreadystatechange=null;b.onopen=null;b.onsend=null;b.onabort=null;b.prototype.open=function(a,f,k,p,q){delete this._headers;3>arguments.length&&(k=!0);this._async=k;var r=this,
s=this.readyState,t;h&&k&&(t=function(){s!=b.DONE&&(e(r),r.abort())},window.attachEvent("onunload",t));b.onopen&&b.onopen.apply(this,arguments);4<arguments.length?this._object.open(a,f,k,p,q):3<arguments.length?this._object.open(a,f,k,p):this._object.open(a,f,k);this.readyState=b.OPENED;c(this);this._object.onreadystatechange=function(){if(!g||k)r.readyState=r._object.readyState,d(r),r._aborted?r.readyState=b.UNSENT:(r.readyState==b.DONE&&(delete r._data,e(r),h&&k&&window.detachEvent("onunload",t)),
s!=r.readyState&&c(r),s=r.readyState)}};b.prototype.send=function(a){b.onsend&&b.onsend.apply(this,arguments);arguments.length||(a=null);a&&a.nodeType&&(a=window.XMLSerializer?(new window.XMLSerializer).serializeToString(a):a.xml,this._headers["Content-Type"]||this._object.setRequestHeader("Content-Type","application/xml"));this._data=a;a:if(this._object.send(this._data),g&&!this._async)for(this.readyState=b.OPENED,d(this);this.readyState<b.DONE;)if(this.readyState++,c(this),this._aborted)break a};
b.prototype.abort=function(){b.onabort&&b.onabort.apply(this,arguments);this.readyState>b.UNSENT&&(this._aborted=!0);this._object.abort();e(this);this.readyState=b.UNSENT;delete this._data};b.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders()};b.prototype.getResponseHeader=function(a){return this._object.getResponseHeader(a)};b.prototype.setRequestHeader=function(a,b){this._headers||(this._headers={});this._headers[a]=b;return this._object.setRequestHeader(a,b)};
b.prototype.addEventListener=function(a,b,c){for(var d=0,e;e=this._listeners[d];d++)if(e[0]==a&&e[1]==b&&e[2]==c)return;this._listeners.push([a,b,c])};b.prototype.removeEventListener=function(a,b,c){for(var d=0,e;(e=this._listeners[d])&&(e[0]!=a||e[1]!=b||e[2]!=c);d++);e&&this._listeners.splice(d,1)};b.prototype.dispatchEvent=function(a){a={type:a.type,target:this,currentTarget:this,eventPhase:2,bubbles:a.bubbles,cancelable:a.cancelable,timeStamp:a.timeStamp,stopPropagation:function(){},preventDefault:function(){},
initEvent:function(){}};"readystatechange"==a.type&&this.onreadystatechange&&(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[a]);for(var b=0,c;c=this._listeners[b];b++)c[0]!=a.type||c[2]||(c[1].handleEvent||c[1]).apply(this,[a])};b.prototype.toString=function(){return"[object XMLHttpRequest]"};b.toString=function(){return"[XMLHttpRequest]"};window.Function.prototype.apply||(window.Function.prototype.apply=function(a,b){b||(b=[]);a.__func=this;a.__func(b[0],b[1],b[2],b[3],
b[4]);delete a.__func});OpenLayers.Request||(OpenLayers.Request={});OpenLayers.Request.XMLHttpRequest=b})();OpenLayers.ProxyHost="";OpenLayers.Request||(OpenLayers.Request={});
OpenLayers.Util.extend(OpenLayers.Request,{DEFAULT_CONFIG:{method:"GET",url:window.location.href,async:!0,user:void 0,password:void 0,params:null,proxy:OpenLayers.ProxyHost,headers:{},data:null,callback:function(){},success:null,failure:null,scope:null},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(a,b){var c=0!==a.indexOf("http"),d=!c&&a.match(this.URL_SPLIT_REGEX);if(d){var e=window.location,c=d[1]==e.protocol&&d[3]==
e.hostname,d=d[4],e=e.port;if(80!=d&&""!=d||"80"!=e&&""!=e)c=c&&d==e}c||b&&(a="function"==typeof b?b(a):b+encodeURIComponent(a));return a},issue:function(a){var b=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});a=a||{};a.headers=a.headers||{};a=OpenLayers.Util.applyDefaults(a,b);a.headers=OpenLayers.Util.applyDefaults(a.headers,b.headers);var b=!1,c;for(c in a.headers)a.headers.hasOwnProperty(c)&&"x-requested-with"===c.toLowerCase()&&(b=!0);!1===b&&(a.headers["X-Requested-With"]=
"XMLHttpRequest");var d=new OpenLayers.Request.XMLHttpRequest,e=OpenLayers.Util.urlAppend(a.url,OpenLayers.Util.getParameterString(a.params||{})),e=OpenLayers.Request.makeSameOrigin(e,a.proxy);d.open(a.method,e,a.async,a.user,a.password);for(var f in a.headers)d.setRequestHeader(f,a.headers[f]);var g=this.events,h=this;d.onreadystatechange=function(){d.readyState==OpenLayers.Request.XMLHttpRequest.DONE&&!1!==g.triggerEvent("complete",{request:d,config:a,requestUrl:e})&&h.runCallbacks({request:d,config:a,
requestUrl:e})};!1===a.async?d.send(a.data):window.setTimeout(function(){0!==d.readyState&&d.send(a.data)},0);return d},runCallbacks:function(a){var b=a.request,c=a.config,d=c.scope?OpenLayers.Function.bind(c.callback,c.scope):c.callback,e;c.success&&(e=c.scope?OpenLayers.Function.bind(c.success,c.scope):c.success);var f;c.failure&&(f=c.scope?OpenLayers.Function.bind(c.failure,c.scope):c.failure);"file:"==OpenLayers.Util.createUrlObject(c.url).protocol&&b.responseText&&(b.status=200);d(b);if(!b.status||
200<=b.status&&300>b.status)this.events.triggerEvent("success",a),e&&e(b);b.status&&(200>b.status||300<=b.status)&&(this.events.triggerEvent("failure",a),f&&f(b))},GET:function(a){a=OpenLayers.Util.extend(a,{method:"GET"});return OpenLayers.Request.issue(a)},POST:function(a){a=OpenLayers.Util.extend(a,{method:"POST"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)},PUT:function(a){a=
OpenLayers.Util.extend(a,{method:"PUT"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)},DELETE:function(a){a=OpenLayers.Util.extend(a,{method:"DELETE"});return OpenLayers.Request.issue(a)},HEAD:function(a){a=OpenLayers.Util.extend(a,{method:"HEAD"});return OpenLayers.Request.issue(a)},OPTIONS:function(a){a=OpenLayers.Util.extend(a,{method:"OPTIONS"});return OpenLayers.Request.issue(a)}});OpenLayers.Layer.ArcIMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{ClientVersion:"9.2",ServiceName:""},featureCoordSys:"4326",filterCoordSys:"4326",layers:null,async:!0,name:"ArcIMS",isBaseLayer:!0,DEFAULT_OPTIONS:{tileSize:new OpenLayers.Size(512,512),featureCoordSys:"4326",filterCoordSys:"4326",layers:null,isBaseLayer:!0,async:!0,name:"ArcIMS"},initialize:function(a,b,c){this.tileSize=new OpenLayers.Size(512,512);this.params=OpenLayers.Util.applyDefaults({ServiceName:c.serviceName},
this.DEFAULT_PARAMS);this.options=OpenLayers.Util.applyDefaults(c,this.DEFAULT_OPTIONS);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,this.params,c]);this.transparent&&(this.isBaseLayer||(this.isBaseLayer=!1),"image/jpeg"==this.format&&(this.format=OpenLayers.Util.alphaHack()?"image/gif":"image/png"));null===this.options.layers&&(this.options.layers=[])},getURL:function(a){var b="";a=this.adjustBounds(a);a=new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options,{requesttype:"image",
envelope:a.toArray(),tileSize:this.tileSize}));a=new OpenLayers.Request.POST({url:this.getFullRequestString(),data:a.write(),async:!1});null!=a&&(b=a.responseXML,b&&b.documentElement||(b=a.responseText),b=(new OpenLayers.Format.ArcXML).read(b),b=this.getUrlOrImage(b.image.output));return b},getURLasync:function(a,b,c){a=this.adjustBounds(a);a=new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options,{requesttype:"image",envelope:a.toArray(),tileSize:this.tileSize}));OpenLayers.Request.POST({url:this.getFullRequestString(),
async:!0,data:a.write(),callback:function(a){var e=a.responseXML;e&&e.documentElement||(e=a.responseText);a=(new OpenLayers.Format.ArcXML).read(e);b.call(c,this.getUrlOrImage(a.image.output))},scope:this})},getUrlOrImage:function(a){var b="";a.url?b=a.url:a.data&&(b="data:image/"+a.type+";base64,"+a.data);return b},setLayerQuery:function(a,b){for(var c=0;c<this.options.layers.length;c++)if(a==this.options.layers[c].id){this.options.layers[c].query=b;return}this.options.layers.push({id:a,visible:!0,
query:b})},getFeatureInfo:function(a,b,c){var d=c.buffer||1,e=c.callback||function(){},f=c.scope||window,g={};OpenLayers.Util.extend(g,this.options);g.requesttype="feature";a instanceof OpenLayers.LonLat?(g.polygon=null,g.envelope=[a.lon-d,a.lat-d,a.lon+d,a.lat+d]):a instanceof OpenLayers.Geometry.Polygon&&(g.envelope=null,g.polygon=a);var h=new OpenLayers.Format.ArcXML(g);OpenLayers.Util.extend(h.request.get_feature,c);h.request.get_feature.layer=b.id;"number"==typeof b.query.accuracy?h.request.get_feature.query.accuracy=
b.query.accuracy:(a=this.map.getCenter(),c=this.map.getViewPortPxFromLonLat(a),c.x++,c=this.map.getLonLatFromPixel(c),h.request.get_feature.query.accuracy=c.lon-a.lon);h.request.get_feature.query.where=b.query.where;h.request.get_feature.query.spatialfilter.relation="area_intersection";OpenLayers.Request.POST({url:this.getFullRequestString({CustomService:"Query"}),data:h.write(),callback:function(a){a=h.parseResponse(a.responseText);h.iserror()?e.call(f,null):e.call(f,a.features)}})},clone:function(a){null==
a&&(a=new OpenLayers.Layer.ArcIMS(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.ArcIMS"});OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,slideRatio:null,buttons:null,position:null,initialize:function(a){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onButtonClick);this.removeButtons();this.position=this.buttons=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},
setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.register("buttonclick",this,this.onButtonClick)},draw:function(a){OpenLayers.Control.prototype.draw.apply(this,arguments);a=this.position;this.buttons=[];var b={w:18,h:18},c=new OpenLayers.Pixel(a.x+b.w/2,a.y);this._addButton("panup","north-mini.png",c,b);a.y=c.y+b.h;this._addButton("panleft","west-mini.png",a,b);this._addButton("panright","east-mini.png",a.add(b.w,0),b);this._addButton("pandown","south-mini.png",
c.add(0,2*b.h),b);this._addButton("zoomin","zoom-plus-mini.png",c.add(0,3*b.h+5),b);this._addButton("zoomworld","zoom-world-mini.png",c.add(0,4*b.h+5),b);this._addButton("zoomout","zoom-minus-mini.png",c.add(0,5*b.h+5),b);return this.div},_addButton:function(a,b,c,d){b=OpenLayers.Util.getImageLocation(b);c=OpenLayers.Util.createAlphaImageDiv(this.id+"_"+a,c,d,b,"absolute");c.style.cursor="pointer";this.div.appendChild(c);c.action=a;c.className="olButton";this.buttons.push(c);return c},_removeButton:function(a){this.div.removeChild(a);
OpenLayers.Util.removeItem(this.buttons,a)},removeButtons:function(){for(var a=this.buttons.length-1;0<=a;--a)this._removeButton(this.buttons[a])},onButtonClick:function(a){switch(a.buttonElement.action){case "panup":this.map.pan(0,-this.getSlideFactor("h"));break;case "pandown":this.map.pan(0,this.getSlideFactor("h"));break;case "panleft":this.map.pan(-this.getSlideFactor("w"),0);break;case "panright":this.map.pan(this.getSlideFactor("w"),0);break;case "zoomin":this.map.zoomIn();break;case "zoomout":this.map.zoomOut();
break;case "zoomworld":this.map.zoomToMaxExtent()}},getSlideFactor:function(a){return this.slideRatio?this.map.getSize()[a]*this.slideRatio:this.slideFactor},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Control.PanZoomBar=OpenLayers.Class(OpenLayers.Control.PanZoom,{zoomStopWidth:18,zoomStopHeight:11,slider:null,sliderEvents:null,zoombarDiv:null,zoomWorldIcon:!1,panIcons:!0,forceFixedZoomLevel:!1,mouseDragStart:null,deltaY:null,zoomStart:null,destroy:function(){this._removeZoomBar();this.map.events.un({changebaselayer:this.redraw,updatesize:this.redraw,scope:this});OpenLayers.Control.PanZoom.prototype.destroy.apply(this,arguments);delete this.mouseDragStart;delete this.zoomStart},setMap:function(a){OpenLayers.Control.PanZoom.prototype.setMap.apply(this,
arguments);this.map.events.on({changebaselayer:this.redraw,updatesize:this.redraw,scope:this})},redraw:function(){null!=this.div&&(this.removeButtons(),this._removeZoomBar());this.draw()},draw:function(a){OpenLayers.Control.prototype.draw.apply(this,arguments);a=this.position.clone();this.buttons=[];var b={w:18,h:18};if(this.panIcons){var c=new OpenLayers.Pixel(a.x+b.w/2,a.y),d=b.w;this.zoomWorldIcon&&(c=new OpenLayers.Pixel(a.x+b.w,a.y));this._addButton("panup","north-mini.png",c,b);a.y=c.y+b.h;
this._addButton("panleft","west-mini.png",a,b);this.zoomWorldIcon&&(this._addButton("zoomworld","zoom-world-mini.png",a.add(b.w,0),b),d*=2);this._addButton("panright","east-mini.png",a.add(d,0),b);this._addButton("pandown","south-mini.png",c.add(0,2*b.h),b);this._addButton("zoomin","zoom-plus-mini.png",c.add(0,3*b.h+5),b);c=this._addZoomBar(c.add(0,4*b.h+5));this._addButton("zoomout","zoom-minus-mini.png",c,b)}else this._addButton("zoomin","zoom-plus-mini.png",a,b),c=this._addZoomBar(a.add(0,b.h)),
this._addButton("zoomout","zoom-minus-mini.png",c,b),this.zoomWorldIcon&&(c=c.add(0,b.h+3),this._addButton("zoomworld","zoom-world-mini.png",c,b));return this.div},_addZoomBar:function(a){var b=OpenLayers.Util.getImageLocation("slider.png"),c=this.id+"_"+this.map.id,d=this.map.getMinZoom(),e=this.map.getNumZoomLevels()-1-this.map.getZoom(),e=OpenLayers.Util.createAlphaImageDiv(c,a.add(-1,e*this.zoomStopHeight),{w:20,h:9},b,"absolute");e.style.cursor="move";this.slider=e;this.sliderEvents=new OpenLayers.Events(this,
e,null,!0,{includeXY:!0});this.sliderEvents.on({touchstart:this.zoomBarDown,touchmove:this.zoomBarDrag,touchend:this.zoomBarUp,mousedown:this.zoomBarDown,mousemove:this.zoomBarDrag,mouseup:this.zoomBarUp});var f={w:this.zoomStopWidth,h:this.zoomStopHeight*(this.map.getNumZoomLevels()-d)},b=OpenLayers.Util.getImageLocation("zoombar.png"),c=null;OpenLayers.Util.alphaHack()?(c=this.id+"_"+this.map.id,c=OpenLayers.Util.createAlphaImageDiv(c,a,{w:f.w,h:this.zoomStopHeight},b,"absolute",null,"crop"),c.style.height=
f.h+"px"):c=OpenLayers.Util.createDiv("OpenLayers_Control_PanZoomBar_Zoombar"+this.map.id,a,f,b);c.style.cursor="pointer";c.className="olButton";this.zoombarDiv=c;this.div.appendChild(c);this.startTop=parseInt(c.style.top);this.div.appendChild(e);this.map.events.register("zoomend",this,this.moveZoomBar);return a=a.add(0,this.zoomStopHeight*(this.map.getNumZoomLevels()-d))},_removeZoomBar:function(){this.sliderEvents.un({touchstart:this.zoomBarDown,touchmove:this.zoomBarDrag,touchend:this.zoomBarUp,
mousedown:this.zoomBarDown,mousemove:this.zoomBarDrag,mouseup:this.zoomBarUp});this.sliderEvents.destroy();this.div.removeChild(this.zoombarDiv);this.zoombarDiv=null;this.div.removeChild(this.slider);this.slider=null;this.map.events.unregister("zoomend",this,this.moveZoomBar)},onButtonClick:function(a){OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this,arguments);if(a.buttonElement===this.zoombarDiv){var b=a.buttonXY.y/this.zoomStopHeight;if(this.forceFixedZoomLevel||!this.map.fractionalZoom)b=
Math.floor(b);b=this.map.getNumZoomLevels()-1-b;b=Math.min(Math.max(b,0),this.map.getNumZoomLevels()-1);this.map.zoomTo(b)}},passEventToSlider:function(a){this.sliderEvents.handleBrowserEvent(a)},zoomBarDown:function(a){if(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))this.map.events.on({touchmove:this.passEventToSlider,mousemove:this.passEventToSlider,mouseup:this.passEventToSlider,scope:this}),this.mouseDragStart=a.xy.clone(),this.zoomStart=a.xy.clone(),this.div.style.cursor=
"move",this.zoombarDiv.offsets=null,OpenLayers.Event.stop(a)},zoomBarDrag:function(a){if(null!=this.mouseDragStart){var b=this.mouseDragStart.y-a.xy.y,c=OpenLayers.Util.pagePosition(this.zoombarDiv);0<a.clientY-c[1]&&a.clientY-c[1]<parseInt(this.zoombarDiv.style.height)-2&&(b=parseInt(this.slider.style.top)-b,this.slider.style.top=b+"px",this.mouseDragStart=a.xy.clone());this.deltaY=this.zoomStart.y-a.xy.y;OpenLayers.Event.stop(a)}},zoomBarUp:function(a){if((OpenLayers.Event.isLeftClick(a)||"touchend"===
a.type)&&this.mouseDragStart){this.div.style.cursor="";this.map.events.un({touchmove:this.passEventToSlider,mouseup:this.passEventToSlider,mousemove:this.passEventToSlider,scope:this});var b=this.map.zoom;!this.forceFixedZoomLevel&&this.map.fractionalZoom?(b+=this.deltaY/this.zoomStopHeight,b=Math.min(Math.max(b,0),this.map.getNumZoomLevels()-1)):(b+=this.deltaY/this.zoomStopHeight,b=Math.max(Math.round(b),0));this.map.zoomTo(b);this.zoomStart=this.mouseDragStart=null;this.deltaY=0;OpenLayers.Event.stop(a)}},
moveZoomBar:function(){var a=(this.map.getNumZoomLevels()-1-this.map.getZoom())*this.zoomStopHeight+this.startTop+1;this.slider.style.top=a+"px"},CLASS_NAME:"OpenLayers.Control.PanZoomBar"});OpenLayers.Format.WFSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.0",CLASS_NAME:"OpenLayers.Format.WFSCapabilities"});OpenLayers.Format.WFSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{wfs:"http://www.opengis.net/wfs",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",ows:"http://www.opengis.net/ows"},errorProperty:"featureTypeList",defaultPrefix:"wfs",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{wfs:{WFS_Capabilities:function(a,
b){this.readChildNodes(a,b)},FeatureTypeList:function(a,b){b.featureTypeList={featureTypes:[]};this.readChildNodes(a,b.featureTypeList)},FeatureType:function(a,b){var c={};this.readChildNodes(a,c);b.featureTypes.push(c)},Name:function(a,b){var c=this.getChildValue(a);c&&(c=c.split(":"),b.name=c.pop(),0<c.length&&(b.featureNS=this.lookupNamespaceURI(a,c[0])))},Title:function(a,b){var c=this.getChildValue(a);c&&(b.title=c)},Abstract:function(a,b){var c=this.getChildValue(a);c&&(b["abstract"]=c)}}},
CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1"});OpenLayers.Format.WFSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1,{regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},readers:{wfs:OpenLayers.Util.applyDefaults({DefaultSRS:function(a,b){var c=this.getChildValue(a);c&&(b.srs=c)}},OpenLayers.Format.WFSCapabilities.v1.prototype.readers.wfs),ows:OpenLayers.Format.OWSCommon.v1.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1_1_0"});OpenLayers.Layer.Image=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!0,url:null,extent:null,size:null,tile:null,aspectRatio:null,initialize:function(a,b,c,d,e){this.url=b;this.maxExtent=this.extent=c;this.size=d;OpenLayers.Layer.prototype.initialize.apply(this,[a,e]);this.aspectRatio=this.extent.getHeight()/this.size.h/(this.extent.getWidth()/this.size.w)},destroy:function(){this.tile&&(this.removeTileMonitoringHooks(this.tile),this.tile.destroy(),this.tile=null);OpenLayers.Layer.prototype.destroy.apply(this,
arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Image(this.name,this.url,this.extent,this.size,this.getOptions()));return a=OpenLayers.Layer.prototype.clone.apply(this,[a])},setMap:function(a){null==this.options.maxResolution&&(this.options.maxResolution=this.aspectRatio*this.extent.getWidth()/this.size.w);OpenLayers.Layer.prototype.setMap.apply(this,arguments)},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var d=null==this.tile;if(b||d){this.setTileSize();
var e=this.map.getLayerPxFromLonLat({lon:this.extent.left,lat:this.extent.top});d?(this.tile=new OpenLayers.Tile.Image(this,e,this.extent,null,this.tileSize),this.addTileMonitoringHooks(this.tile)):(this.tile.size=this.tileSize.clone(),this.tile.position=e.clone());this.tile.draw()}},setTileSize:function(){var a=this.extent.getWidth()/this.map.getResolution(),b=this.extent.getHeight()/this.map.getResolution();this.tileSize=new OpenLayers.Size(a,b)},addTileMonitoringHooks:function(a){a.onLoadStart=
function(){this.events.triggerEvent("loadstart")};a.events.register("loadstart",this,a.onLoadStart);a.onLoadEnd=function(){this.events.triggerEvent("loadend")};a.events.register("loadend",this,a.onLoadEnd);a.events.register("unload",this,a.onLoadEnd)},removeTileMonitoringHooks:function(a){a.unload();a.events.un({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,scope:this})},setUrl:function(a){this.url=a;this.tile.draw()},getURL:function(a){return this.url},CLASS_NAME:"OpenLayers.Layer.Image"});OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:!0,autoDestroy:!0,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a;this.active=!1},destroy:function(){this.deactivate();this.options=this.layer=null},setLayer:function(a){this.layer=a},activate:function(){return this.active?!1:this.active=!0},deactivate:function(){return this.active?(this.active=!1,!0):!1},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Strategy.Save=OpenLayers.Class(OpenLayers.Strategy,{events:null,auto:!1,timer:null,initialize:function(a){OpenLayers.Strategy.prototype.initialize.apply(this,[a]);this.events=new OpenLayers.Events(this)},activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a&&this.auto)if("number"===typeof this.auto)this.timer=window.setInterval(OpenLayers.Function.bind(this.save,this),1E3*this.auto);else this.layer.events.on({featureadded:this.triggerSave,afterfeaturemodified:this.triggerSave,
scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.auto&&("number"===typeof this.auto?window.clearInterval(this.timer):this.layer.events.un({featureadded:this.triggerSave,afterfeaturemodified:this.triggerSave,scope:this}));return a},triggerSave:function(a){var b=a.feature;b.state!==OpenLayers.State.INSERT&&b.state!==OpenLayers.State.UPDATE&&b.state!==OpenLayers.State.DELETE||this.save([a.feature])},save:function(a){a||(a=this.layer.features);
this.events.triggerEvent("start",{features:a});var b=this.layer.projection,c=this.layer.map.getProjectionObject();if(!c.equals(b)){for(var d=a.length,e=Array(d),f,g,h=0;h<d;++h)f=a[h],g=f.clone(),g.fid=f.fid,g.state=f.state,f.url&&(g.url=f.url),g._original=f,g.geometry.transform(c,b),e[h]=g;a=e}this.layer.protocol.commit(a,{callback:this.onCommit,scope:this})},onCommit:function(a){var b={response:a};if(a.success()){for(var c=a.reqFeatures,d,e=[],f=a.insertIds||[],g=0,h=0,k=c.length;h<k;++h)if(d=c[h],
d=d._original||d,a=d.state)a==OpenLayers.State.DELETE?e.push(d):a==OpenLayers.State.INSERT&&(d.fid=f[g],++g),d.state=null;0<e.length&&this.layer.destroyFeatures(e);this.events.triggerEvent("success",b)}else this.events.triggerEvent("fail",b)},CLASS_NAME:"OpenLayers.Strategy.Save"});OpenLayers.Events.featureclick=OpenLayers.Class({cache:null,map:null,provides:["featureclick","nofeatureclick","featureover","featureout"],initialize:function(a){this.target=a;if(a.object instanceof OpenLayers.Map)this.setMap(a.object);else if(a.object instanceof OpenLayers.Layer.Vector)a.object.map?this.setMap(a.object.map):a.object.events.register("added",this,function(b){this.setMap(a.object.map)});else throw"Listeners for '"+this.provides.join("', '")+"' events can only be registered for OpenLayers.Layer.Vector or OpenLayers.Map instances";
for(var b=this.provides.length-1;0<=b;--b)a.extensions[this.provides[b]]=!0},setMap:function(a){this.map=a;this.cache={};a.events.register("mousedown",this,this.start,{extension:!0});a.events.register("mouseup",this,this.onClick,{extension:!0});a.events.register("touchstart",this,this.start,{extension:!0});a.events.register("touchmove",this,this.cancel,{extension:!0});a.events.register("touchend",this,this.onClick,{extension:!0});a.events.register("mousemove",this,this.onMousemove,{extension:!0})},
start:function(a){this.startEvt=a},cancel:function(a){delete this.startEvt},onClick:function(a){if(this.startEvt&&("touchend"===a.type||OpenLayers.Event.isLeftClick(a))){a=this.getFeatures(this.startEvt);delete this.startEvt;for(var b,c,d={},e=0,f=a.length;e<f&&(b=a[e],c=b.layer,d[c.id]=!0,b=this.triggerEvent("featureclick",{feature:b}),!1!==b);++e);e=0;for(f=this.map.layers.length;e<f;++e)c=this.map.layers[e],c instanceof OpenLayers.Layer.Vector&&!d[c.id]&&this.triggerEvent("nofeatureclick",{layer:c})}},
onMousemove:function(a){delete this.startEvt;var b=this.getFeatures(a),c={};a=[];for(var d,e=0,f=b.length;e<f;++e)d=b[e],c[d.id]=d,this.cache[d.id]||a.push(d);var b=[],g;for(g in this.cache)d=this.cache[g],d.layer&&d.layer.map?c[d.id]||b.push(d):delete this.cache[g];e=0;for(f=a.length;e<f&&(d=a[e],this.cache[d.id]=d,g=this.triggerEvent("featureover",{feature:d}),!1!==g);++e);e=0;for(f=b.length;e<f&&(d=b[e],delete this.cache[d.id],g=this.triggerEvent("featureout",{feature:d}),!1!==g);++e);},triggerEvent:function(a,
b){var c=b.feature?b.feature.layer:b.layer,d=this.target.object;if(d instanceof OpenLayers.Map||d===c)return this.target.triggerEvent(a,b)},getFeatures:function(a){var b=a.clientX,c=a.clientY,d=[],e=[],f=[],g,h,k,l;for(l=this.map.layers.length-1;0<=l;--l)if(g=this.map.layers[l],"none"!==g.div.style.display)if(g.renderer instanceof OpenLayers.Renderer.Elements){if(g instanceof OpenLayers.Layer.Vector)for(h=document.elementFromPoint(b,c);h&&h._featureId;)(k=g.getFeatureById(h._featureId))?(d.push(k),
h.style.display="none",e.push(h),h=document.elementFromPoint(b,c)):h=!1;f.push(g);g.div.style.display="none"}else g.renderer instanceof OpenLayers.Renderer.Canvas&&(k=g.renderer.getFeatureIdFromEvent(a))&&(d.push(k),f.push(g));l=0;for(a=e.length;l<a;++l)e[l].style.display="";for(l=f.length-1;0<=l;--l)f[l].div.style.display="block";return d},destroy:function(){for(var a=this.provides.length-1;0<=a;--a)delete this.target.extensions[this.provides[a]];this.map.events.un({mousemove:this.onMousemove,mousedown:this.start,
mouseup:this.onClick,touchstart:this.start,touchmove:this.cancel,touchend:this.onClick,scope:this});delete this.cache;delete this.map;delete this.target}});OpenLayers.Events.nofeatureclick=OpenLayers.Events.featureclick;OpenLayers.Events.featureover=OpenLayers.Events.featureclick;OpenLayers.Events.featureout=OpenLayers.Events.featureclick;OpenLayers.Format.GPX=OpenLayers.Class(OpenLayers.Format.XML,{defaultDesc:"No description available",extractWaypoints:!0,extractTracks:!0,extractRoutes:!0,extractAttributes:!0,namespaces:{gpx:"http://www.topografix.com/GPX/1/1",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd",creator:"OpenLayers",initialize:function(a){this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,
[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=[];if(this.extractTracks)for(var c=a.getElementsByTagName("trk"),d=0,e=c.length;d<e;d++){var f={};this.extractAttributes&&(f=this.parseAttributes(c[d]));for(var g=this.getElementsByTagNameNS(c[d],c[d].namespaceURI,"trkseg"),h=0,k=g.length;h<k;h++){var l=this.extractSegment(g[h],"trkpt");b.push(new OpenLayers.Feature.Vector(l,f))}}if(this.extractRoutes)for(e=a.getElementsByTagName("rte"),c=0,d=
e.length;c<d;c++)f={},this.extractAttributes&&(f=this.parseAttributes(e[c])),g=this.extractSegment(e[c],"rtept"),b.push(new OpenLayers.Feature.Vector(g,f));if(this.extractWaypoints)for(a=a.getElementsByTagName("wpt"),c=0,e=a.length;c<e;c++)f={},this.extractAttributes&&(f=this.parseAttributes(a[c])),d=new OpenLayers.Geometry.Point(a[c].getAttribute("lon"),a[c].getAttribute("lat")),b.push(new OpenLayers.Feature.Vector(d,f));if(this.internalProjection&&this.externalProjection)for(f=0,a=b.length;f<a;f++)b[f].geometry.transform(this.externalProjection,
this.internalProjection);return b},extractSegment:function(a,b){for(var c=this.getElementsByTagNameNS(a,a.namespaceURI,b),d=[],e=0,f=c.length;e<f;e++)d.push(new OpenLayers.Geometry.Point(c[e].getAttribute("lon"),c[e].getAttribute("lat")));return new OpenLayers.Geometry.LineString(d)},parseAttributes:function(a){var b={};a=a.firstChild;for(var c,d;a;)1==a.nodeType&&a.firstChild&&(c=a.firstChild,3==c.nodeType||4==c.nodeType)&&(d=a.prefix?a.nodeName.split(":")[1]:a.nodeName,"trkseg"!=d&&"rtept"!=d&&
(b[d]=c.nodeValue)),a=a.nextSibling;return b},write:function(a,b){a=OpenLayers.Util.isArray(a)?a:[a];var c=this.createElementNS(this.namespaces.gpx,"gpx");c.setAttribute("version","1.1");c.setAttribute("creator",this.creator);this.setAttributes(c,{"xsi:schemaLocation":this.schemaLocation});b&&"object"==typeof b&&c.appendChild(this.buildMetadataNode(b));for(var d=0,e=a.length;d<e;d++)c.appendChild(this.buildFeatureNode(a[d]));return OpenLayers.Format.XML.prototype.write.apply(this,[c])},buildMetadataNode:function(a){for(var b=
["name","desc","author"],c=this.createElementNS(this.namespaces.gpx,"metadata"),d=0;d<b.length;d++){var e=b[d];if(a[e]){var f=this.createElementNS(this.namespaces.gpx,e);f.appendChild(this.createTextNode(a[e]));c.appendChild(f)}}return c},buildFeatureNode:function(a){var b=a.geometry,b=b.clone();this.internalProjection&&this.externalProjection&&b.transform(this.internalProjection,this.externalProjection);if("OpenLayers.Geometry.Point"==b.CLASS_NAME){var c=this.buildWptNode(b);this.appendAttributesNode(c,
a);return c}c=this.createElementNS(this.namespaces.gpx,"trk");this.appendAttributesNode(c,a);a=this.buildTrkSegNode(b);a=OpenLayers.Util.isArray(a)?a:[a];for(var b=0,d=a.length;b<d;b++)c.appendChild(a[b]);return c},buildTrkSegNode:function(a){var b,c,d,e;if("OpenLayers.Geometry.LineString"==a.CLASS_NAME||"OpenLayers.Geometry.LinearRing"==a.CLASS_NAME){b=this.createElementNS(this.namespaces.gpx,"trkseg");c=0;for(d=a.components.length;c<d;c++)e=a.components[c],b.appendChild(this.buildTrkPtNode(e));
return b}b=[];c=0;for(d=a.components.length;c<d;c++)b.push(this.buildTrkSegNode(a.components[c]));return b},buildTrkPtNode:function(a){var b=this.createElementNS(this.namespaces.gpx,"trkpt");b.setAttribute("lon",a.x);b.setAttribute("lat",a.y);return b},buildWptNode:function(a){var b=this.createElementNS(this.namespaces.gpx,"wpt");b.setAttribute("lon",a.x);b.setAttribute("lat",a.y);return b},appendAttributesNode:function(a,b){var c=this.createElementNS(this.namespaces.gpx,"name");c.appendChild(this.createTextNode(b.attributes.name||
b.id));a.appendChild(c);c=this.createElementNS(this.namespaces.gpx,"desc");c.appendChild(this.createTextNode(b.attributes.description||this.defaultDesc));a.appendChild(c)},CLASS_NAME:"OpenLayers.Format.GPX"});OpenLayers.Format.WMSDescribeLayer=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.1",CLASS_NAME:"OpenLayers.Format.WMSDescribeLayer"});OpenLayers.Format.WMSDescribeLayer.v1_1_1=OpenLayers.Class(OpenLayers.Format.WMSDescribeLayer,{initialize:function(a){OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));for(var b=a.documentElement.childNodes,c={layerDescriptions:[]},d,e,f=0;f<b.length;++f)if(d=b[f],e=d.nodeName,"LayerDescription"==e){e=d.getAttribute("name");var g="",h="",k="";d.getAttribute("owsType")?(g=d.getAttribute("owsType"),
h=d.getAttribute("owsURL")):""!=d.getAttribute("wfs")?(g="WFS",h=d.getAttribute("wfs")):""!=d.getAttribute("wcs")&&(g="WCS",h=d.getAttribute("wcs"));d=d.getElementsByTagName("Query");0<d.length&&((k=d[0].getAttribute("typeName"))||(k=d[0].getAttribute("typename")));d={layerName:e,owsType:g,owsURL:h,typeName:k};c.layerDescriptions.push(d);c.length=c.layerDescriptions.length;c[c.length-1]=d}else if("ServiceException"==e)return{error:(new OpenLayers.Format.OGCExceptionReport).read(a)};return c},CLASS_NAME:"OpenLayers.Format.WMSDescribeLayer.v1_1_1"});
OpenLayers.Format.WMSDescribeLayer.v1_1_0=OpenLayers.Format.WMSDescribeLayer.v1_1_1;OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,sphericalMercator:!1,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a||this.name,b||this.url,{},c])},clone:function(a){null==a&&(a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
[a])},getURL:function(a){a=this.getXYZ(a);var b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(""+a.x+a.y+a.z,b));return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.getServerResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w));a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h));b=this.getServerZoom();if(this.wrapDateLine)var d=Math.pow(2,b),c=(c%d+d)%d;return{x:c,y:a,z:b}},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,
arguments);this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.bottom))},CLASS_NAME:"OpenLayers.Layer.XYZ"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],attribution:"&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors",sphericalMercator:!0,wrapDateLine:!0,tileOptions:null,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=
OpenLayers.Util.extend({crossOriginKeyword:"anonymous"},this.options&&this.options.tileOptions)},clone:function(a){null==a&&(a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Renderer=OpenLayers.Class({container:null,root:null,extent:null,locked:!1,size:null,resolution:null,map:null,featureDx:0,initialize:function(a,b){this.container=OpenLayers.Util.getElement(a);OpenLayers.Util.extend(this,b)},destroy:function(){this.map=this.resolution=this.size=this.extent=this.container=null},supported:function(){return!1},setExtent:function(a,b){this.extent=a.clone();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var c=a.getWidth()/this.map.getExtent().getWidth();
a=a.scale(1/c);this.extent=a.wrapDateLine(this.map.getMaxExtent()).scale(c)}b&&(this.resolution=null);return!0},setSize:function(a){this.size=a.clone();this.resolution=null},getResolution:function(){return this.resolution=this.resolution||this.map.getResolution()},drawFeature:function(a,b){null==b&&(b=a.style);if(a.geometry){var c=a.geometry.getBounds();if(c){var d;this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&(d=this.map.getMaxExtent());c.intersectsBounds(this.extent,{worldBounds:d})?this.calculateFeatureDx(c,
d):b={display:"none"};c=this.drawGeometry(a.geometry,b,a.id);if("none"!=b.display&&b.label&&!1!==c){d=a.geometry.getCentroid();if(b.labelXOffset||b.labelYOffset){var e=isNaN(b.labelXOffset)?0:b.labelXOffset,f=isNaN(b.labelYOffset)?0:b.labelYOffset,g=this.getResolution();d.move(e*g,f*g)}this.drawText(a.id,b,d)}else this.removeText(a.id);return c}}},calculateFeatureDx:function(a,b){this.featureDx=0;if(b){var c=b.getWidth();this.featureDx=Math.round(((a.left+a.right)/2-(this.extent.left+this.extent.right)/
2)/c)*c}},drawGeometry:function(a,b,c){},drawText:function(a,b,c){},removeText:function(a){},clear:function(){},getFeatureIdFromEvent:function(a){},eraseFeatures:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0,c=a.length;b<c;++b){var d=a[b];this.eraseGeometry(d.geometry,d.id);this.removeText(d.id)}},eraseGeometry:function(a,b){},moveRoot:function(a){},getRenderLayerId:function(){return this.container.id},applyDefaultSymbolizer:function(a){var b=OpenLayers.Util.extend({},OpenLayers.Renderer.defaultSymbolizer);
!1===a.stroke&&(delete b.strokeWidth,delete b.strokeColor);!1===a.fill&&delete b.fillColor;OpenLayers.Util.extend(b,a);return b},CLASS_NAME:"OpenLayers.Renderer"});OpenLayers.Renderer.defaultSymbolizer={fillColor:"#000000",strokeColor:"#000000",strokeWidth:2,fillOpacity:1,strokeOpacity:1,pointRadius:0,labelAlign:"cm"};
OpenLayers.Renderer.symbol={star:[350,75,379,161,469,161,397,215,423,301,350,250,277,301,303,215,231,161,321,161,350,75],cross:[4,0,6,0,6,4,10,4,10,6,6,6,6,10,4,10,4,6,0,6,0,4,4,4,4,0],x:[0,0,25,0,50,35,75,0,100,0,65,50,100,100,75,100,50,65,25,100,0,100,35,50,0,0],square:[0,0,0,1,1,1,1,0,0,0],triangle:[0,10,10,10,5,0,0,10]};OpenLayers.Renderer.Canvas=OpenLayers.Class(OpenLayers.Renderer,{hitDetection:!0,hitOverflow:0,canvas:null,features:null,pendingRedraw:!1,cachedSymbolBounds:{},initialize:function(a,b){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.root=document.createElement("canvas");this.container.appendChild(this.root);this.canvas=this.root.getContext("2d");this.features={};this.hitDetection&&(this.hitCanvas=document.createElement("canvas"),this.hitContext=this.hitCanvas.getContext("2d"))},
setExtent:function(){OpenLayers.Renderer.prototype.setExtent.apply(this,arguments);return!1},eraseGeometry:function(a,b){this.eraseFeatures(this.features[b][0])},supported:function(){return OpenLayers.CANVAS_SUPPORTED},setSize:function(a){this.size=a.clone();var b=this.root;b.style.width=a.w+"px";b.style.height=a.h+"px";b.width=a.w;b.height=a.h;this.resolution=null;this.hitDetection&&(b=this.hitCanvas,b.style.width=a.w+"px",b.style.height=a.h+"px",b.width=a.w,b.height=a.h)},drawFeature:function(a,
b){var c;if(a.geometry){b=this.applyDefaultSymbolizer(b||a.style);c=a.geometry.getBounds();var d;this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&(d=this.map.getMaxExtent());d=c&&c.intersectsBounds(this.extent,{worldBounds:d});(c="none"!==b.display&&!!c&&d)?this.features[a.id]=[a,b]:delete this.features[a.id];this.pendingRedraw=!0}this.pendingRedraw&&!this.locked&&(this.redraw(),this.pendingRedraw=!1);return c},drawGeometry:function(a,b,c){var d=a.CLASS_NAME;if("OpenLayers.Geometry.Collection"==
d||"OpenLayers.Geometry.MultiPoint"==d||"OpenLayers.Geometry.MultiLineString"==d||"OpenLayers.Geometry.MultiPolygon"==d)for(d=0;d<a.components.length;d++)this.drawGeometry(a.components[d],b,c);else switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":this.drawPoint(a,b,c);break;case "OpenLayers.Geometry.LineString":this.drawLineString(a,b,c);break;case "OpenLayers.Geometry.LinearRing":this.drawLinearRing(a,b,c);break;case "OpenLayers.Geometry.Polygon":this.drawPolygon(a,b,c)}},drawExternalGraphic:function(a,
b,c){var d=new Image,e=b.title||b.graphicTitle;e&&(d.title=e);var f=b.graphicWidth||b.graphicHeight,g=b.graphicHeight||b.graphicWidth,f=f?f:2*b.pointRadius,g=g?g:2*b.pointRadius,h=void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*f),k=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*g),l=b.graphicOpacity||b.fillOpacity;d.onload=OpenLayers.Function.bind(function(){if(this.features[c]){var b=this.getLocalXY(a),e=b[0],b=b[1];if(!isNaN(e)&&!isNaN(b)){var e=e+h|0,b=b+k|0,p=this.canvas;p.globalAlpha=l;var q=
OpenLayers.Renderer.Canvas.drawImageScaleFactor||(OpenLayers.Renderer.Canvas.drawImageScaleFactor=/android 2.1/.test(navigator.userAgent.toLowerCase())?320/window.screen.width:1);p.drawImage(d,e*q,b*q,f*q,g*q);this.hitDetection&&(this.setHitContextStyle("fill",c),this.hitContext.fillRect(e,b,f,g))}}},this);d.src=b.externalGraphic},drawNamedSymbol:function(a,b,c){var d,e,f,g;f=Math.PI/180;var h=OpenLayers.Renderer.symbol[b.graphicName];if(!h)throw Error(b.graphicName+" is not a valid symbol name");
if(!(!h.length||2>h.length||(a=this.getLocalXY(a),e=a[0],g=a[1],isNaN(e)||isNaN(g)))){this.canvas.lineCap="round";this.canvas.lineJoin="round";this.hitDetection&&(this.hitContext.lineCap="round",this.hitContext.lineJoin="round");if(b.graphicName in this.cachedSymbolBounds)d=this.cachedSymbolBounds[b.graphicName];else{d=new OpenLayers.Bounds;for(a=0;a<h.length;a+=2)d.extend(new OpenLayers.LonLat(h[a],h[a+1]));this.cachedSymbolBounds[b.graphicName]=d}this.canvas.save();this.hitDetection&&this.hitContext.save();
this.canvas.translate(e,g);this.hitDetection&&this.hitContext.translate(e,g);a=f*b.rotation;isNaN(a)||(this.canvas.rotate(a),this.hitDetection&&this.hitContext.rotate(a));f=2*b.pointRadius/Math.max(d.getWidth(),d.getHeight());this.canvas.scale(f,f);this.hitDetection&&this.hitContext.scale(f,f);a=d.getCenterLonLat().lon;d=d.getCenterLonLat().lat;this.canvas.translate(-a,-d);this.hitDetection&&this.hitContext.translate(-a,-d);g=b.strokeWidth;b.strokeWidth=g/f;if(!1!==b.fill){this.setCanvasStyle("fill",
b);this.canvas.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.canvas.lineTo(d,e);this.canvas.closePath();this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",c,b);this.hitContext.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.hitContext.lineTo(d,e);this.hitContext.closePath();this.hitContext.fill()}}if(!1!==b.stroke){this.setCanvasStyle("stroke",b);this.canvas.beginPath();for(a=0;a<h.length;a+=2)d=h[a],
e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.canvas.lineTo(d,e);this.canvas.closePath();this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",c,b,f);this.hitContext.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.hitContext.moveTo(d,e),this.hitContext.lineTo(d,e);this.hitContext.closePath();this.hitContext.stroke()}}b.strokeWidth=g;this.canvas.restore();this.hitDetection&&this.hitContext.restore();this.setCanvasStyle("reset")}},setCanvasStyle:function(a,b){"fill"===
a?(this.canvas.globalAlpha=b.fillOpacity,this.canvas.fillStyle=b.fillColor):"stroke"===a?(this.canvas.globalAlpha=b.strokeOpacity,this.canvas.strokeStyle=b.strokeColor,this.canvas.lineWidth=b.strokeWidth):(this.canvas.globalAlpha=0,this.canvas.lineWidth=1)},featureIdToHex:function(a){a=Number(a.split("_").pop())+1;16777216<=a&&(this.hitOverflow=a-16777215,a=a%16777216+1);a="000000"+a.toString(16);var b=a.length;return a="#"+a.substring(b-6,b)},setHitContextStyle:function(a,b,c,d){b=this.featureIdToHex(b);
"fill"==a?(this.hitContext.globalAlpha=1,this.hitContext.fillStyle=b):"stroke"==a?(this.hitContext.globalAlpha=1,this.hitContext.strokeStyle=b,"undefined"===typeof d?this.hitContext.lineWidth=c.strokeWidth+2:isNaN(d)||(this.hitContext.lineWidth=c.strokeWidth+2/d)):(this.hitContext.globalAlpha=0,this.hitContext.lineWidth=1)},drawPoint:function(a,b,c){if(!1!==b.graphic)if(b.externalGraphic)this.drawExternalGraphic(a,b,c);else if(b.graphicName&&"circle"!=b.graphicName)this.drawNamedSymbol(a,b,c);else{var d=
this.getLocalXY(a);a=d[0];d=d[1];if(!isNaN(a)&&!isNaN(d)){var e=2*Math.PI,f=b.pointRadius;!1!==b.fill&&(this.setCanvasStyle("fill",b),this.canvas.beginPath(),this.canvas.arc(a,d,f,0,e,!0),this.canvas.fill(),this.hitDetection&&(this.setHitContextStyle("fill",c,b),this.hitContext.beginPath(),this.hitContext.arc(a,d,f,0,e,!0),this.hitContext.fill()));!1!==b.stroke&&(this.setCanvasStyle("stroke",b),this.canvas.beginPath(),this.canvas.arc(a,d,f,0,e,!0),this.canvas.stroke(),this.hitDetection&&(this.setHitContextStyle("stroke",
c,b),this.hitContext.beginPath(),this.hitContext.arc(a,d,f,0,e,!0),this.hitContext.stroke()),this.setCanvasStyle("reset"))}}},drawLineString:function(a,b,c){b=OpenLayers.Util.applyDefaults({fill:!1},b);this.drawLinearRing(a,b,c)},drawLinearRing:function(a,b,c){!1!==b.fill&&(this.setCanvasStyle("fill",b),this.renderPath(this.canvas,a,b,c,"fill"),this.hitDetection&&(this.setHitContextStyle("fill",c,b),this.renderPath(this.hitContext,a,b,c,"fill")));!1!==b.stroke&&(this.setCanvasStyle("stroke",b),this.renderPath(this.canvas,
a,b,c,"stroke"),this.hitDetection&&(this.setHitContextStyle("stroke",c,b),this.renderPath(this.hitContext,a,b,c,"stroke")));this.setCanvasStyle("reset")},renderPath:function(a,b,c,d,e){b=b.components;c=b.length;a.beginPath();d=this.getLocalXY(b[0]);var f=d[1];if(!isNaN(d[0])&&!isNaN(f)){a.moveTo(d[0],d[1]);for(d=1;d<c;++d)f=this.getLocalXY(b[d]),a.lineTo(f[0],f[1]);"fill"===e?a.fill():a.stroke()}},drawPolygon:function(a,b,c){a=a.components;var d=a.length;this.drawLinearRing(a[0],b,c);for(var e=1;e<
d;++e)this.canvas.globalCompositeOperation="destination-out",this.hitDetection&&(this.hitContext.globalCompositeOperation="destination-out"),this.drawLinearRing(a[e],OpenLayers.Util.applyDefaults({stroke:!1,fillOpacity:1},b),c),this.canvas.globalCompositeOperation="source-over",this.hitDetection&&(this.hitContext.globalCompositeOperation="source-over"),this.drawLinearRing(a[e],OpenLayers.Util.applyDefaults({fill:!1},b),c)},drawText:function(a,b){var c=this.getLocalXY(a);this.setCanvasStyle("reset");
this.canvas.fillStyle=b.fontColor;this.canvas.globalAlpha=b.fontOpacity||1;var d=[b.fontStyle?b.fontStyle:"normal","normal",b.fontWeight?b.fontWeight:"normal",b.fontSize?b.fontSize:"1em",b.fontFamily?b.fontFamily:"sans-serif"].join(" "),e=b.label.split("\n"),f=e.length;if(this.canvas.fillText){this.canvas.font=d;this.canvas.textAlign=OpenLayers.Renderer.Canvas.LABEL_ALIGN[b.labelAlign[0]]||"center";this.canvas.textBaseline=OpenLayers.Renderer.Canvas.LABEL_ALIGN[b.labelAlign[1]]||"middle";var g=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[1]];
null==g&&(g=-0.5);d=this.canvas.measureText("Mg").height||this.canvas.measureText("xx").width;c[1]+=d*g*(f-1);for(g=0;g<f;g++)b.labelOutlineWidth&&(this.canvas.save(),this.canvas.globalAlpha=b.labelOutlineOpacity||b.fontOpacity||1,this.canvas.strokeStyle=b.labelOutlineColor,this.canvas.lineWidth=b.labelOutlineWidth,this.canvas.strokeText(e[g],c[0],c[1]+d*g+1),this.canvas.restore()),this.canvas.fillText(e[g],c[0],c[1]+d*g)}else if(this.canvas.mozDrawText){this.canvas.mozTextStyle=d;var h=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[0]];
null==h&&(h=-0.5);g=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[1]];null==g&&(g=-0.5);d=this.canvas.mozMeasureText("xx");c[1]+=d*(1+g*f);for(g=0;g<f;g++){var k=c[0]+h*this.canvas.mozMeasureText(e[g]),l=c[1]+g*d;this.canvas.translate(k,l);this.canvas.mozDrawText(e[g]);this.canvas.translate(-k,-l)}}this.setCanvasStyle("reset")},getLocalXY:function(a){var b=this.getResolution(),c=this.extent;return[(a.x-this.featureDx)/b+-c.left/b,c.top/b-a.y/b]},clear:function(){var a=this.root.height,b=this.root.width;
this.canvas.clearRect(0,0,b,a);this.features={};this.hitDetection&&this.hitContext.clearRect(0,0,b,a)},getFeatureIdFromEvent:function(a){var b;if(this.hitDetection&&"none"!==this.root.style.display&&!this.map.dragging&&(a=a.xy,a=this.hitContext.getImageData(a.x|0,a.y|0,1,1).data,255===a[3]&&(a=a[2]+256*(a[1]+256*a[0])))){a="OpenLayers_Feature_Vector_"+(a-1+this.hitOverflow);try{b=this.features[a][0]}catch(c){}}return b},eraseFeatures:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0;b<a.length;++b)delete this.features[a[b].id];
this.redraw()},redraw:function(){if(!this.locked){var a=this.root.height,b=this.root.width;this.canvas.clearRect(0,0,b,a);this.hitDetection&&this.hitContext.clearRect(0,0,b,a);var a=[],c,d,e=this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&this.map.getMaxExtent(),f;for(f in this.features)this.features.hasOwnProperty(f)&&(b=this.features[f][0],c=b.geometry,this.calculateFeatureDx(c.getBounds(),e),d=this.features[f][1],this.drawGeometry(c,d,b.id),d.label&&a.push([b,d]));b=0;for(c=a.length;b<c;++b)f=
a[b],this.drawText(f[0].geometry.getCentroid(),f[1])}},CLASS_NAME:"OpenLayers.Renderer.Canvas"});OpenLayers.Renderer.Canvas.LABEL_ALIGN={l:"left",r:"right",t:"top",b:"bottom"};OpenLayers.Renderer.Canvas.LABEL_FACTOR={l:0,r:-1,t:0,b:-1};OpenLayers.Renderer.Canvas.drawImageScaleFactor=null;OpenLayers.Format.OSM=OpenLayers.Class(OpenLayers.Format.XML,{checkTags:!1,interestingTagsExclude:null,areaTags:null,initialize:function(a){var b={interestingTagsExclude:"source source_ref source:ref history attribution created_by".split(" "),areaTags:"area building leisure tourism ruins historic landuse military natural sport".split(" ")},b=OpenLayers.Util.extend(b,a),c={};for(a=0;a<b.interestingTagsExclude.length;a++)c[b.interestingTagsExclude[a]]=!0;b.interestingTagsExclude=c;c={};for(a=0;a<b.areaTags.length;a++)c[b.areaTags[a]]=
!0;b.areaTags=c;this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[b])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=this.getNodes(a),c=this.getWays(a);a=Array(c.length);for(var d=0;d<c.length;d++){for(var e=Array(c[d].nodes.length),f=this.isWayArea(c[d])?1:0,g=0;g<c[d].nodes.length;g++){var h=b[c[d].nodes[g]],k=new OpenLayers.Geometry.Point(h.lon,h.lat);k.osm_id=parseInt(c[d].nodes[g]);
e[g]=k;h.used=!0}h=null;h=f?new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(e)):new OpenLayers.Geometry.LineString(e);this.internalProjection&&this.externalProjection&&h.transform(this.externalProjection,this.internalProjection);e=new OpenLayers.Feature.Vector(h,c[d].tags);e.osm_id=parseInt(c[d].id);e.fid="way."+e.osm_id;a[d]=e}for(var l in b){h=b[l];if(!h.used||this.checkTags){c=null;if(this.checkTags){c=this.getTags(h.node,!0);if(h.used&&!c[1])continue;c=c[0]}else c=this.getTags(h.node);
e=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(h.lon,h.lat),c);this.internalProjection&&this.externalProjection&&e.geometry.transform(this.externalProjection,this.internalProjection);e.osm_id=parseInt(l);e.fid="node."+e.osm_id;a.push(e)}h.node=null}return a},getNodes:function(a){a=a.getElementsByTagName("node");for(var b={},c=0;c<a.length;c++){var d=a[c],e=d.getAttribute("id");b[e]={lat:d.getAttribute("lat"),lon:d.getAttribute("lon"),node:d}}return b},getWays:function(a){a=a.getElementsByTagName("way");
for(var b=[],c=0;c<a.length;c++){var d=a[c],e={id:d.getAttribute("id")};e.tags=this.getTags(d);d=d.getElementsByTagName("nd");e.nodes=Array(d.length);for(var f=0;f<d.length;f++)e.nodes[f]=d[f].getAttribute("ref");b.push(e)}return b},getTags:function(a,b){for(var c=a.getElementsByTagName("tag"),d={},e=!1,f=0;f<c.length;f++){var g=c[f].getAttribute("k");d[g]=c[f].getAttribute("v");b&&(this.interestingTagsExclude[g]||(e=!0))}return b?[d,e]:d},isWayArea:function(a){var b=!1,c=!1;a.nodes[0]==a.nodes[a.nodes.length-
1]&&(b=!0);if(this.checkTags)for(var d in a.tags)if(this.areaTags[d]){c=!0;break}return b&&(this.checkTags?c:!0)},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);this.osm_id=1;this.created_nodes={};var b=this.createElementNS(null,"osm");b.setAttribute("version","0.5");b.setAttribute("generator","OpenLayers "+OpenLayers.VERSION_NUMBER);for(var c=a.length-1;0<=c;c--)for(var d=this.createFeatureNodes(a[c]),e=0;e<d.length;e++)b.appendChild(d[e]);return OpenLayers.Format.XML.prototype.write.apply(this,
[b])},createFeatureNodes:function(a){var b=[],c=a.geometry.CLASS_NAME,c=c.substring(c.lastIndexOf(".")+1),c=c.toLowerCase();(c=this.createXML[c])&&(b=c.apply(this,[a]));return b},createXML:{point:function(a){var b=null,c=a.geometry?a.geometry:a;this.internalProjection&&this.externalProjection&&(c=c.clone(),c.transform(this.internalProjection,this.externalProjection));var d=!1;a.osm_id?(b=a.osm_id,this.created_nodes[b]&&(d=!0)):(b=-this.osm_id,this.osm_id++);var e=d?this.created_nodes[b]:this.createElementNS(null,
"node");this.created_nodes[b]=e;e.setAttribute("id",b);e.setAttribute("lon",c.x);e.setAttribute("lat",c.y);a.attributes&&this.serializeTags(a,e);this.setState(a,e);return d?[]:[e]},linestring:function(a){var b,c=[],d=a.geometry;a.osm_id?b=a.osm_id:(b=-this.osm_id,this.osm_id++);var e=this.createElementNS(null,"way");e.setAttribute("id",b);for(b=0;b<d.components.length;b++){var f=this.createXML.point.apply(this,[d.components[b]]);if(f.length){var f=f[0],g=f.getAttribute("id");c.push(f)}else g=d.components[b].osm_id,
f=this.created_nodes[g];this.setState(a,f);f=this.createElementNS(null,"nd");f.setAttribute("ref",g);e.appendChild(f)}this.serializeTags(a,e);c.push(e);return c},polygon:function(a){var b=OpenLayers.Util.extend({area:"yes"},a.attributes),b=new OpenLayers.Feature.Vector(a.geometry.components[0],b);b.osm_id=a.osm_id;return this.createXML.linestring.apply(this,[b])}},serializeTags:function(a,b){for(var c in a.attributes){var d=this.createElementNS(null,"tag");d.setAttribute("k",c);d.setAttribute("v",
a.attributes[c]);b.appendChild(d)}},setState:function(a,b){if(a.state){var c=null;switch(a.state){case OpenLayers.State.UPDATE:case OpenLayers.State.DELETE:c="delete"}c&&b.setAttribute("action",c)}},CLASS_NAME:"OpenLayers.Format.OSM"});OpenLayers.Handler.Keyboard=OpenLayers.Class(OpenLayers.Handler,{KEY_EVENTS:["keydown","keyup"],eventListener:null,observeElement:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.eventListener=OpenLayers.Function.bindAsEventListener(this.handleKeyEvent,this)},destroy:function(){this.deactivate();this.eventListener=null;OpenLayers.Handler.prototype.destroy.apply(this,arguments)},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,
arguments)){this.observeElement=this.observeElement||document;for(var a=0,b=this.KEY_EVENTS.length;a<b;a++)OpenLayers.Event.observe(this.observeElement,this.KEY_EVENTS[a],this.eventListener);return!0}return!1},deactivate:function(){var a=!1;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){for(var a=0,b=this.KEY_EVENTS.length;a<b;a++)OpenLayers.Event.stopObserving(this.observeElement,this.KEY_EVENTS[a],this.eventListener);a=!0}return a},handleKeyEvent:function(a){this.checkModifiers(a)&&
this.callback(a.type,[a])},CLASS_NAME:"OpenLayers.Handler.Keyboard"});OpenLayers.Control.ModifyFeature=OpenLayers.Class(OpenLayers.Control,{documentDrag:!1,geometryTypes:null,clickout:!0,toggle:!0,standalone:!1,layer:null,feature:null,vertex:null,vertices:null,virtualVertices:null,handlers:null,deleteCodes:null,virtualStyle:null,vertexRenderIntent:null,mode:null,createVertices:!0,modified:!1,radiusHandle:null,dragHandle:null,onModificationStart:function(){},onModification:function(){},onModificationEnd:function(){},initialize:function(a,b){b=b||{};this.layer=a;this.vertices=
[];this.virtualVertices=[];this.virtualStyle=OpenLayers.Util.extend({},this.layer.style||this.layer.styleMap.createSymbolizer(null,b.vertexRenderIntent));this.virtualStyle.fillOpacity=0.3;this.virtualStyle.strokeOpacity=0.3;this.deleteCodes=[46,68];this.mode=OpenLayers.Control.ModifyFeature.RESHAPE;OpenLayers.Control.prototype.initialize.apply(this,[b]);OpenLayers.Util.isArray(this.deleteCodes)||(this.deleteCodes=[this.deleteCodes]);var c={documentDrag:this.documentDrag,stopDown:!1};this.handlers=
{keyboard:new OpenLayers.Handler.Keyboard(this,{keydown:this.handleKeypress}),drag:new OpenLayers.Handler.Drag(this,{down:function(a){this.vertex=null;(a=this.layer.getFeatureFromEvent(this.handlers.drag.evt))?this.dragStart(a):this.clickout&&(this._unselect=this.feature)},move:function(a){delete this._unselect;this.vertex&&this.dragVertex(this.vertex,a)},up:function(){this.handlers.drag.stopDown=!1;this._unselect&&(this.unselectFeature(this._unselect),delete this._unselect)},done:function(a){this.vertex&&
this.dragComplete(this.vertex)}},c)}},destroy:function(){this.map&&this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this});this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[])},activate:function(){this.moveLayerToTop();this.map.events.on({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this});return this.handlers.keyboard.activate()&&this.handlers.drag.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments)},
deactivate:function(){var a=!1;OpenLayers.Control.prototype.deactivate.apply(this,arguments)&&(this.moveLayerBack(),this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this}),this.layer.removeFeatures(this.vertices,{silent:!0}),this.layer.removeFeatures(this.virtualVertices,{silent:!0}),this.vertices=[],this.handlers.drag.deactivate(),this.handlers.keyboard.deactivate(),(a=this.feature)&&(a.geometry&&a.layer)&&this.unselectFeature(a),a=!0);return a},beforeSelectFeature:function(a){return this.layer.events.triggerEvent("beforefeaturemodified",
{feature:a})},selectFeature:function(a){if(!(this.feature===a||this.geometryTypes&&-1==OpenLayers.Util.indexOf(this.geometryTypes,a.geometry.CLASS_NAME))){!1!==this.beforeSelectFeature(a)&&(this.feature&&this.unselectFeature(this.feature),this.feature=a,this.layer.selectedFeatures.push(a),this.layer.drawFeature(a,"select"),this.modified=!1,this.resetVertices(),this.onModificationStart(this.feature));var b=a.modified;!a.geometry||b&&b.geometry||(this._originalGeometry=a.geometry.clone())}},unselectFeature:function(a){this.layer.removeFeatures(this.vertices,
{silent:!0});this.vertices=[];this.layer.destroyFeatures(this.virtualVertices,{silent:!0});this.virtualVertices=[];this.dragHandle&&(this.layer.destroyFeatures([this.dragHandle],{silent:!0}),delete this.dragHandle);this.radiusHandle&&(this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),delete this.radiusHandle);this.layer.drawFeature(this.feature,"default");this.feature=null;OpenLayers.Util.removeItem(this.layer.selectedFeatures,a);this.onModificationEnd(a);this.layer.events.triggerEvent("afterfeaturemodified",
{feature:a,modified:this.modified});this.modified=!1},dragStart:function(a){var b="OpenLayers.Geometry.Point"==a.geometry.CLASS_NAME;this.standalone||(a._sketch||!b)&&a._sketch||(this.toggle&&this.feature===a&&(this._unselect=a),this.selectFeature(a));if(a._sketch||b)this.vertex=a,this.handlers.drag.stopDown=!0},dragVertex:function(a,b){var c=this.map.getLonLatFromViewPortPx(b),d=a.geometry;d.move(c.lon-d.x,c.lat-d.y);this.modified=!0;"OpenLayers.Geometry.Point"==this.feature.geometry.CLASS_NAME?
this.layer.events.triggerEvent("vertexmodified",{vertex:a.geometry,feature:this.feature,pixel:b}):(a._index?(a.geometry.parent.addComponent(a.geometry,a._index),delete a._index,OpenLayers.Util.removeItem(this.virtualVertices,a),this.vertices.push(a)):a==this.dragHandle?(this.layer.removeFeatures(this.vertices,{silent:!0}),this.vertices=[],this.radiusHandle&&(this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),this.radiusHandle=null)):a!==this.radiusHandle&&this.layer.events.triggerEvent("vertexmodified",
{vertex:a.geometry,feature:this.feature,pixel:b}),0<this.virtualVertices.length&&(this.layer.destroyFeatures(this.virtualVertices,{silent:!0}),this.virtualVertices=[]),this.layer.drawFeature(this.feature,this.standalone?void 0:"select"));this.layer.drawFeature(a)},dragComplete:function(a){this.resetVertices();this.setFeatureState();this.onModification(this.feature);this.layer.events.triggerEvent("featuremodified",{feature:this.feature})},setFeatureState:function(){if(this.feature.state!=OpenLayers.State.INSERT&&
this.feature.state!=OpenLayers.State.DELETE&&(this.feature.state=OpenLayers.State.UPDATE,this.modified&&this._originalGeometry)){var a=this.feature;a.modified=OpenLayers.Util.extend(a.modified,{geometry:this._originalGeometry});delete this._originalGeometry}},resetVertices:function(){0<this.vertices.length&&(this.layer.removeFeatures(this.vertices,{silent:!0}),this.vertices=[]);0<this.virtualVertices.length&&(this.layer.removeFeatures(this.virtualVertices,{silent:!0}),this.virtualVertices=[]);this.dragHandle&&
(this.layer.destroyFeatures([this.dragHandle],{silent:!0}),this.dragHandle=null);this.radiusHandle&&(this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),this.radiusHandle=null);this.feature&&"OpenLayers.Geometry.Point"!=this.feature.geometry.CLASS_NAME&&(this.mode&OpenLayers.Control.ModifyFeature.DRAG&&this.collectDragHandle(),this.mode&(OpenLayers.Control.ModifyFeature.ROTATE|OpenLayers.Control.ModifyFeature.RESIZE)&&this.collectRadiusHandle(),this.mode&OpenLayers.Control.ModifyFeature.RESHAPE&&
(this.mode&OpenLayers.Control.ModifyFeature.RESIZE||this.collectVertices()))},handleKeypress:function(a){var b=a.keyCode;this.feature&&-1!=OpenLayers.Util.indexOf(this.deleteCodes,b)&&(b=this.layer.getFeatureFromEvent(this.handlers.drag.evt))&&(-1!=OpenLayers.Util.indexOf(this.vertices,b)&&!this.handlers.drag.dragging&&b.geometry.parent)&&(b.geometry.parent.removeComponent(b.geometry),this.layer.events.triggerEvent("vertexremoved",{vertex:b.geometry,feature:this.feature,pixel:a.xy}),this.layer.drawFeature(this.feature,
this.standalone?void 0:"select"),this.modified=!0,this.resetVertices(),this.setFeatureState(),this.onModification(this.feature),this.layer.events.triggerEvent("featuremodified",{feature:this.feature}))},collectVertices:function(){function a(c){var d,e,f;if("OpenLayers.Geometry.Point"==c.CLASS_NAME)e=new OpenLayers.Feature.Vector(c),e._sketch=!0,e.renderIntent=b.vertexRenderIntent,b.vertices.push(e);else{f=c.components.length;"OpenLayers.Geometry.LinearRing"==c.CLASS_NAME&&(f-=1);for(d=0;d<f;++d)e=
c.components[d],"OpenLayers.Geometry.Point"==e.CLASS_NAME?(e=new OpenLayers.Feature.Vector(e),e._sketch=!0,e.renderIntent=b.vertexRenderIntent,b.vertices.push(e)):a(e);if(b.createVertices&&"OpenLayers.Geometry.MultiPoint"!=c.CLASS_NAME)for(d=0,f=c.components.length;d<f-1;++d){e=c.components[d];var g=c.components[d+1];"OpenLayers.Geometry.Point"==e.CLASS_NAME&&"OpenLayers.Geometry.Point"==g.CLASS_NAME&&(e=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point((e.x+g.x)/2,(e.y+g.y)/2),null,b.virtualStyle),
e.geometry.parent=c,e._index=d+1,e._sketch=!0,b.virtualVertices.push(e))}}}this.vertices=[];this.virtualVertices=[];var b=this;a.call(this,this.feature.geometry);this.layer.addFeatures(this.virtualVertices,{silent:!0});this.layer.addFeatures(this.vertices,{silent:!0})},collectDragHandle:function(){var a=this.feature.geometry,b=a.getBounds().getCenterLonLat(),b=new OpenLayers.Geometry.Point(b.lon,b.lat),c=new OpenLayers.Feature.Vector(b);b.move=function(b,c){OpenLayers.Geometry.Point.prototype.move.call(this,
b,c);a.move(b,c)};c._sketch=!0;this.dragHandle=c;this.dragHandle.renderIntent=this.vertexRenderIntent;this.layer.addFeatures([this.dragHandle],{silent:!0})},collectRadiusHandle:function(){var a=this.feature.geometry,b=a.getBounds(),c=b.getCenterLonLat(),d=new OpenLayers.Geometry.Point(c.lon,c.lat),b=new OpenLayers.Geometry.Point(b.right,b.bottom),c=new OpenLayers.Feature.Vector(b),e=this.mode&OpenLayers.Control.ModifyFeature.RESIZE,f=this.mode&OpenLayers.Control.ModifyFeature.RESHAPE,g=this.mode&
OpenLayers.Control.ModifyFeature.ROTATE;b.move=function(b,c){OpenLayers.Geometry.Point.prototype.move.call(this,b,c);var l=this.x-d.x,m=this.y-d.y,n=l-b,p=m-c;if(g){var q=Math.atan2(p,n),q=Math.atan2(m,l)-q,q=q*(180/Math.PI);a.rotate(q,d)}if(e){var r;f?(m/=p,r=l/n/m):(n=Math.sqrt(n*n+p*p),m=Math.sqrt(l*l+m*m)/n);a.resize(m,d,r)}};c._sketch=!0;this.radiusHandle=c;this.radiusHandle.renderIntent=this.vertexRenderIntent;this.layer.addFeatures([this.radiusHandle],{silent:!0})},setMap:function(a){this.handlers.drag.setMap(a);
OpenLayers.Control.prototype.setMap.apply(this,arguments)},handleMapEvents:function(a){"removelayer"!=a.type&&"order"!=a.property||this.moveLayerToTop()},moveLayerToTop:function(){var a=Math.max(this.map.Z_INDEX_BASE.Feature-1,this.layer.getZIndex())+1;this.layer.setZIndex(a)},moveLayerBack:function(){var a=this.layer.getZIndex()-1;a>=this.map.Z_INDEX_BASE.Feature?this.layer.setZIndex(a):this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer))},CLASS_NAME:"OpenLayers.Control.ModifyFeature"});
OpenLayers.Control.ModifyFeature.RESHAPE=1;OpenLayers.Control.ModifyFeature.RESIZE=2;OpenLayers.Control.ModifyFeature.ROTATE=4;OpenLayers.Control.ModifyFeature.DRAG=8;OpenLayers.Layer.Bing=OpenLayers.Class(OpenLayers.Layer.XYZ,{key:null,serverResolutions:[156543.03390625,78271.516953125,39135.7584765625,19567.87923828125,9783.939619140625,4891.9698095703125,2445.9849047851562,1222.9924523925781,611.4962261962891,305.74811309814453,152.87405654907226,76.43702827453613,38.218514137268066,19.109257068634033,9.554628534317017,4.777314267158508,2.388657133579254,1.194328566789627,0.5971642833948135,0.29858214169740677,0.14929107084870338,0.07464553542435169],attributionTemplate:'<span class="olBingAttribution ${type}"><div><a target="_blank" href="http://www.bing.com/maps/"><img src="${logo}" /></a></div>${copyrights}<a style="white-space: nowrap" target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a></span>',
metadata:null,protocolRegex:/^http:/i,type:"Road",culture:"en-US",metadataParams:null,tileOptions:null,protocol:~window.location.href.indexOf("http")?"":"http:",initialize:function(a){a=OpenLayers.Util.applyDefaults({sphericalMercator:!0},a);OpenLayers.Layer.XYZ.prototype.initialize.apply(this,[a.name||"Bing "+(a.type||this.type),null,a]);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"},this.options.tileOptions);this.loadMetadata()},loadMetadata:function(){this._callbackId=
"_callback_"+this.id.replace(/\./g,"_");window[this._callbackId]=OpenLayers.Function.bind(OpenLayers.Layer.Bing.processMetadata,this);var a=OpenLayers.Util.applyDefaults({key:this.key,jsonp:this._callbackId,include:"ImageryProviders"},this.metadataParams),a=this.protocol+"//dev.virtualearth.net/REST/v1/Imagery/Metadata/"+this.type+"?"+OpenLayers.Util.getParameterString(a),b=document.createElement("script");b.type="text/javascript";b.src=a;b.id=this._callbackId;document.getElementsByTagName("head")[0].appendChild(b)},
initLayer:function(){var a=this.metadata.resourceSets[0].resources[0],b=a.imageUrl.replace("{quadkey}","${quadkey}"),b=b.replace("{culture}",this.culture),b=b.replace(this.protocolRegex,this.protocol);this.url=[];for(var c=0;c<a.imageUrlSubdomains.length;++c)this.url.push(b.replace("{subdomain}",a.imageUrlSubdomains[c]));this.addOptions({maxResolution:Math.min(this.serverResolutions[a.zoomMin],this.maxResolution||Number.POSITIVE_INFINITY),numZoomLevels:Math.min(a.zoomMax+1-a.zoomMin,this.numZoomLevels)},
!0);this.isBaseLayer||this.redraw();this.updateAttribution()},getURL:function(a){if(this.url){var b=this.getXYZ(a);a=b.x;for(var c=b.y,b=b.z,d=[],e=b;0<e;--e){var f="0",g=1<<e-1;0!=(a&g)&&f++;0!=(c&g)&&(f++,f++);d.push(f)}d=d.join("");a=this.selectUrl(""+a+c+b,this.url);return OpenLayers.String.format(a,{quadkey:d})}},updateAttribution:function(){var a=this.metadata;if(a.resourceSets&&this.map&&this.map.center){var b=a.resourceSets[0].resources[0],c=this.map.getExtent().transform(this.map.getProjectionObject(),
new OpenLayers.Projection("EPSG:4326")),d=b.imageryProviders||[],e=OpenLayers.Util.indexOf(this.serverResolutions,this.getServerResolution()),b="",f,g,h,k,l,m,n;g=0;for(h=d.length;g<h;++g)for(f=d[g],k=0,l=f.coverageAreas.length;k<l;++k)n=f.coverageAreas[k],m=OpenLayers.Bounds.fromArray(n.bbox,!0),c.intersectsBounds(m)&&(e<=n.zoomMax&&e>=n.zoomMin)&&(b+=f.attribution+" ");a=a.brandLogoUri.replace(this.protocolRegex,this.protocol);this.attribution=OpenLayers.String.format(this.attributionTemplate,{type:this.type.toLowerCase(),
logo:a,copyrights:b});this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"attribution"})}},setMap:function(){OpenLayers.Layer.XYZ.prototype.setMap.apply(this,arguments);this.map.events.register("moveend",this,this.updateAttribution)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Bing(this.options));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},destroy:function(){this.map&&this.map.events.unregister("moveend",this,this.updateAttribution);OpenLayers.Layer.XYZ.prototype.destroy.apply(this,
arguments)},CLASS_NAME:"OpenLayers.Layer.Bing"});OpenLayers.Layer.Bing.processMetadata=function(a){this.metadata=a;this.initLayer();a=document.getElementById(this._callbackId);a.parentNode.removeChild(a);window[this._callbackId]=void 0;delete this._callbackId};OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:!0,initialize:function(a,b){this.styles={"default":new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]),select:new OpenLayers.Style(OpenLayers.Feature.Vector.style.select),temporary:new OpenLayers.Style(OpenLayers.Feature.Vector.style.temporary),"delete":new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"])};if(a instanceof OpenLayers.Style)this.styles["default"]=a,this.styles.select=a,this.styles.temporary=a,this.styles["delete"]=
a;else if("object"==typeof a)for(var c in a)if(a[c]instanceof OpenLayers.Style)this.styles[c]=a[c];else if("object"==typeof a[c])this.styles[c]=new OpenLayers.Style(a[c]);else{this.styles["default"]=new OpenLayers.Style(a);this.styles.select=new OpenLayers.Style(a);this.styles.temporary=new OpenLayers.Style(a);this.styles["delete"]=new OpenLayers.Style(a);break}OpenLayers.Util.extend(this,b)},destroy:function(){for(var a in this.styles)this.styles[a].destroy();this.styles=null},createSymbolizer:function(a,
b){a||(a=new OpenLayers.Feature.Vector);this.styles[b]||(b="default");a.renderIntent=b;var c={};this.extendDefault&&"default"!=b&&(c=this.styles["default"].createSymbolizer(a));return OpenLayers.Util.extend(c,this.styles[b].createSymbolizer(a))},addUniqueValueRules:function(a,b,c,d){var e=[],f;for(f in c)e.push(new OpenLayers.Rule({symbolizer:c[f],context:d,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:b,value:f})}));this.styles[a].addRules(e)},CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!1,isFixed:!1,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:!0,style:null,styleMap:null,strategies:null,protocol:null,renderers:["SVG","VML","Canvas"],renderer:null,rendererOptions:null,geometryType:null,drawn:!1,ratio:1,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.renderer&&this.renderer.supported()||this.assignRenderer();this.renderer&&this.renderer.supported()||
(this.renderer=null,this.displayError());this.styleMap||(this.styleMap=new OpenLayers.StyleMap);this.features=[];this.selectedFeatures=[];this.unrenderedFeatures={};if(this.strategies)for(var c=0,d=this.strategies.length;c<d;c++)this.strategies[c].setLayer(this)},destroy:function(){if(this.strategies){var a,b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoDestroy&&a.destroy();this.strategies=null}this.protocol&&(this.protocol.autoDestroy&&this.protocol.destroy(),this.protocol=
null);this.destroyFeatures();this.unrenderedFeatures=this.selectedFeatures=this.features=null;this.renderer&&this.renderer.destroy();this.drawn=this.geometryType=this.renderer=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Vector(this.name,this.getOptions()));a=OpenLayers.Layer.prototype.clone.apply(this,[a]);for(var b=this.features,c=b.length,d=Array(c),e=0;e<c;++e)d[e]=b[e].clone();a.features=d;return a},refresh:function(a){this.calculateInRange()&&
this.visibility&&this.events.triggerEvent("refresh",a)},assignRenderer:function(){for(var a=0,b=this.renderers.length;a<b;a++){var c=this.renderers[a];if((c="function"==typeof c?c:OpenLayers.Renderer[c])&&c.prototype.supported()){this.renderer=new c(this.div,this.rendererOptions);break}}},displayError:function(){this.reportError&&OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",{renderers:this.renderers.join("\n")}))},setMap:function(a){OpenLayers.Layer.prototype.setMap.apply(this,
arguments);if(this.renderer){this.renderer.map=this.map;var b=this.map.getSize();b.w*=this.ratio;b.h*=this.ratio;this.renderer.setSize(b)}else this.map.removeLayer(this)},afterAdd:function(){if(this.strategies){var a,b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoActivate&&a.activate()}},removeMap:function(a){this.drawn=!1;if(this.strategies){var b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoActivate&&a.deactivate()}},onMapResize:function(){OpenLayers.Layer.prototype.onMapResize.apply(this,
arguments);var a=this.map.getSize();a.w*=this.ratio;a.h*=this.ratio;this.renderer.setSize(a)},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var d=!0;if(!c){this.renderer.root.style.visibility="hidden";var d=this.map.getSize(),e=d.w,d=d.h,e=e/2*this.ratio-e/2,d=d/2*this.ratio-d/2,e=e+this.map.layerContainerOriginPx.x,e=-Math.round(e),d=d+this.map.layerContainerOriginPx.y,d=-Math.round(d);this.div.style.left=e+"px";this.div.style.top=d+"px";e=this.map.getExtent().scale(this.ratio);
d=this.renderer.setExtent(e,b);this.renderer.root.style.visibility="visible";!0===OpenLayers.IS_GECKO&&(this.div.scrollLeft=this.div.scrollLeft);if(!b&&d)for(var f in this.unrenderedFeatures)e=this.unrenderedFeatures[f],this.drawFeature(e)}if(!this.drawn||b||!d)for(this.drawn=!0,f=0,d=this.features.length;f<d;f++)this.renderer.locked=f!==d-1,e=this.features[f],this.drawFeature(e)},display:function(a){OpenLayers.Layer.prototype.display.apply(this,arguments);var b=this.div.style.display;b!=this.renderer.root.style.display&&
(this.renderer.root.style.display=b)},addFeatures:function(a,b){OpenLayers.Util.isArray(a)||(a=[a]);var c=!b||!b.silent;if(c){var d={features:a};if(!1===this.events.triggerEvent("beforefeaturesadded",d))return;a=d.features}for(var d=[],e=0,f=a.length;e<f;e++){this.renderer.locked=e!=a.length-1?!0:!1;var g=a[e];if(this.geometryType&&!(g.geometry instanceof this.geometryType))throw new TypeError("addFeatures: component should be an "+this.geometryType.prototype.CLASS_NAME);g.layer=this;!g.style&&this.style&&
(g.style=OpenLayers.Util.extend({},this.style));if(c){if(!1===this.events.triggerEvent("beforefeatureadded",{feature:g}))continue;this.preFeatureInsert(g)}d.push(g);this.features.push(g);this.drawFeature(g);c&&(this.events.triggerEvent("featureadded",{feature:g}),this.onFeatureInsert(g))}c&&this.events.triggerEvent("featuresadded",{features:d})},removeFeatures:function(a,b){if(a&&0!==a.length){if(a===this.features)return this.removeAllFeatures(b);OpenLayers.Util.isArray(a)||(a=[a]);a===this.selectedFeatures&&
(a=a.slice());var c=!b||!b.silent;c&&this.events.triggerEvent("beforefeaturesremoved",{features:a});for(var d=a.length-1;0<=d;d--){this.renderer.locked=0!=d&&a[d-1].geometry?!0:!1;var e=a[d];delete this.unrenderedFeatures[e.id];c&&this.events.triggerEvent("beforefeatureremoved",{feature:e});this.features=OpenLayers.Util.removeItem(this.features,e);e.layer=null;e.geometry&&this.renderer.eraseFeatures(e);-1!=OpenLayers.Util.indexOf(this.selectedFeatures,e)&&OpenLayers.Util.removeItem(this.selectedFeatures,
e);c&&this.events.triggerEvent("featureremoved",{feature:e})}c&&this.events.triggerEvent("featuresremoved",{features:a})}},removeAllFeatures:function(a){a=!a||!a.silent;var b=this.features;a&&this.events.triggerEvent("beforefeaturesremoved",{features:b});for(var c,d=b.length-1;0<=d;d--)c=b[d],a&&this.events.triggerEvent("beforefeatureremoved",{feature:c}),c.layer=null,a&&this.events.triggerEvent("featureremoved",{feature:c});this.renderer.clear();this.features=[];this.unrenderedFeatures={};this.selectedFeatures=
[];a&&this.events.triggerEvent("featuresremoved",{features:b})},destroyFeatures:function(a,b){void 0==a&&(a=this.features);if(a){this.removeFeatures(a,b);for(var c=a.length-1;0<=c;c--)a[c].destroy()}},drawFeature:function(a,b){if(this.drawn){if("object"!=typeof b){b||a.state!==OpenLayers.State.DELETE||(b="delete");var c=b||a.renderIntent;(b=a.style||this.style)||(b=this.styleMap.createSymbolizer(a,c))}c=this.renderer.drawFeature(a,b);!1===c||null===c?this.unrenderedFeatures[a.id]=a:delete this.unrenderedFeatures[a.id]}},
eraseFeatures:function(a){this.renderer.eraseFeatures(a)},getFeatureFromEvent:function(a){if(!this.renderer)throw Error("getFeatureFromEvent called on layer with no renderer. This usually means you destroyed a layer, but not some handler which is associated with it.");var b=null;(a=this.renderer.getFeatureIdFromEvent(a))&&(b="string"===typeof a?this.getFeatureById(a):a);return b},getFeatureBy:function(a,b){for(var c=null,d=0,e=this.features.length;d<e;++d)if(this.features[d][a]==b){c=this.features[d];
break}return c},getFeatureById:function(a){return this.getFeatureBy("id",a)},getFeatureByFid:function(a){return this.getFeatureBy("fid",a)},getFeaturesByAttribute:function(a,b){var c,d,e=this.features.length,f=[];for(c=0;c<e;c++)(d=this.features[c])&&d.attributes&&d.attributes[a]===b&&f.push(d);return f},onFeatureInsert:function(a){},preFeatureInsert:function(a){},getDataExtent:function(){var a=null,b=this.features;if(b&&0<b.length)for(var c=null,d=0,e=b.length;d<e;d++)if(c=b[d].geometry)null===a&&
(a=new OpenLayers.Bounds),a.extend(c.getBounds());return a},CLASS_NAME:"OpenLayers.Layer.Vector"});OpenLayers.Layer.PointGrid=OpenLayers.Class(OpenLayers.Layer.Vector,{dx:null,dy:null,ratio:1.5,maxFeatures:250,rotation:0,origin:null,gridBounds:null,initialize:function(a){a=a||{};OpenLayers.Layer.Vector.prototype.initialize.apply(this,[a.name,a])},setMap:function(a){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);a.events.register("moveend",this,this.onMoveEnd)},removeMap:function(a){a.events.unregister("moveend",this,this.onMoveEnd);OpenLayers.Layer.Vector.prototype.removeMap.apply(this,
arguments)},setRatio:function(a){this.ratio=a;this.updateGrid(!0)},setMaxFeatures:function(a){this.maxFeatures=a;this.updateGrid(!0)},setSpacing:function(a,b){this.dx=a;this.dy=b||a;this.updateGrid(!0)},setOrigin:function(a){this.origin=a;this.updateGrid(!0)},getOrigin:function(){this.origin||(this.origin=this.map.getExtent().getCenterLonLat());return this.origin},setRotation:function(a){this.rotation=a;this.updateGrid(!0)},onMoveEnd:function(){this.updateGrid()},getViewBounds:function(){var a=this.map.getExtent();
if(this.rotation){var b=this.getOrigin(),b=new OpenLayers.Geometry.Point(b.lon,b.lat),a=a.toGeometry();a.rotate(-this.rotation,b);a=a.getBounds()}return a},updateGrid:function(a){if(a||this.invalidBounds()){var b=this.getViewBounds(),c=this.getOrigin();a=new OpenLayers.Geometry.Point(c.lon,c.lat);var d=b.getWidth(),e=b.getHeight(),f=d/e,g=Math.sqrt(this.dx*this.dy*this.maxFeatures/f),d=Math.min(d*this.ratio,g*f),e=Math.min(e*this.ratio,g),b=b.getCenterLonLat();this.gridBounds=new OpenLayers.Bounds(b.lon-
d/2,b.lat-e/2,b.lon+d/2,b.lat+e/2);for(var b=Math.floor(e/this.dy),d=Math.floor(d/this.dx),e=c.lon+this.dx*Math.ceil((this.gridBounds.left-c.lon)/this.dx),c=c.lat+this.dy*Math.ceil((this.gridBounds.bottom-c.lat)/this.dy),g=Array(b*d),h,k=0;k<d;++k)for(var f=e+k*this.dx,l=0;l<b;++l)h=c+l*this.dy,h=new OpenLayers.Geometry.Point(f,h),this.rotation&&h.rotate(this.rotation,a),g[k*b+l]=new OpenLayers.Feature.Vector(h);this.destroyFeatures(this.features,{silent:!0});this.addFeatures(g,{silent:!0})}},invalidBounds:function(){return!this.gridBounds||
!this.gridBounds.containsBounds(this.getViewBounds())},CLASS_NAME:"OpenLayers.Layer.PointGrid"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,interval:0,maxDelta:Number.POSITIVE_INFINITY,delta:0,cumulative:!0,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this)},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null},onWheelEvent:function(a){if(this.map&&this.checkModifiers(a)){for(var b=
!1,c=!1,d=!1,e=OpenLayers.Event.element(a);null!=e&&!d&&!b;){if(!b)try{var f,b=(f=e.currentStyle?e.currentStyle.overflow:document.defaultView.getComputedStyle(e,null).getPropertyValue("overflow"))&&"auto"==f||"scroll"==f}catch(g){}if(!c&&(c=OpenLayers.Element.hasClass(e,"olScrollable"),!c))for(var d=0,h=this.map.layers.length;d<h;d++){var k=this.map.layers[d];if(e==k.div||e==k.pane){c=!0;break}}d=e==this.map.div;e=e.parentNode}if(!b&&d){if(c)if(b=0,a.wheelDelta?(b=a.wheelDelta,0===b%160&&(b*=0.75),
b/=120):a.detail&&(b=-(a.detail/Math.abs(a.detail))),this.delta+=b,window.clearTimeout(this._timeoutId),this.interval&&Math.abs(this.delta)<this.maxDelta){var l=OpenLayers.Util.extend({},a);this._timeoutId=window.setTimeout(OpenLayers.Function.bind(function(){this.wheelZoom(l)},this),this.interval)}else this.wheelZoom(a);OpenLayers.Event.stop(a)}}},wheelZoom:function(a){var b=this.delta;this.delta=0;b&&(a.xy=this.map.events.getMousePosition(a),0>b?this.callback("down",[a,this.cumulative?Math.max(-this.maxDelta,
b):-1]):this.callback("up",[a,this.cumulative?Math.min(this.maxDelta,b):1]))},activate:function(a){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",b);OpenLayers.Event.observe(window,"mousewheel",b);OpenLayers.Event.observe(document,"mousewheel",b);return!0}return!1},deactivate:function(a){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.stopObserving(window,
"DOMMouseScroll",b);OpenLayers.Event.stopObserving(window,"mousewheel",b);OpenLayers.Event.stopObserving(document,"mousewheel",b);return!0}return!1},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Symbolizer=OpenLayers.Class({zIndex:0,initialize:function(a){OpenLayers.Util.extend(this,a)},clone:function(){return new (eval(this.CLASS_NAME))(OpenLayers.Util.extend({},this))},CLASS_NAME:"OpenLayers.Symbolizer"});OpenLayers.Symbolizer.Raster=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Raster"});OpenLayers.Rule=OpenLayers.Class({id:null,name:null,title:null,description:null,context:null,filter:null,elseFilter:!1,symbolizer:null,symbolizers:null,minScaleDenominator:null,maxScaleDenominator:null,initialize:function(a){this.symbolizer={};OpenLayers.Util.extend(this,a);this.symbolizers&&delete this.symbolizer;this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a in this.symbolizer)this.symbolizer[a]=null;this.symbolizer=null;delete this.symbolizers},evaluate:function(a){var b=
this.getContext(a),c=!0;if(this.minScaleDenominator||this.maxScaleDenominator)var d=a.layer.map.getScale();this.minScaleDenominator&&(c=d>=OpenLayers.Style.createLiteral(this.minScaleDenominator,b));c&&this.maxScaleDenominator&&(c=d<OpenLayers.Style.createLiteral(this.maxScaleDenominator,b));c&&this.filter&&(c="OpenLayers.Filter.FeatureId"==this.filter.CLASS_NAME?this.filter.evaluate(a):this.filter.evaluate(b));return c},getContext:function(a){var b=this.context;b||(b=a.attributes||a.data);"function"==
typeof this.context&&(b=this.context(a));return b},clone:function(){var a=OpenLayers.Util.extend({},this);if(this.symbolizers){var b=this.symbolizers.length;a.symbolizers=Array(b);for(var c=0;c<b;++c)a.symbolizers[c]=this.symbolizers[c].clone()}else{a.symbolizer={};for(var d in this.symbolizer)b=this.symbolizer[d],c=typeof b,"object"===c?a.symbolizer[d]=OpenLayers.Util.extend({},b):"string"===c&&(a.symbolizer[d]=b)}a.filter=this.filter&&this.filter.clone();a.context=this.context&&OpenLayers.Util.extend({},
this.context);return new OpenLayers.Rule(a)},CLASS_NAME:"OpenLayers.Rule"});OpenLayers.Format.SLD=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{profile:null,defaultVersion:"1.0.0",stringifyOutput:!0,namedLayersAsArray:!1,CLASS_NAME:"OpenLayers.Format.SLD"});OpenLayers.Symbolizer.Polygon=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Polygon"});OpenLayers.Format.GML.v2=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",initialize:function(a){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[a])},readers:{gml:OpenLayers.Util.applyDefaults({outerBoundaryIs:function(a,b){var c={};this.readChildNodes(a,c);b.outer=c.components[0]},innerBoundaryIs:function(a,b){var c={};this.readChildNodes(a,c);b.inner.push(c.components[0])},Box:function(a,b){var c=
{};this.readChildNodes(a,c);b.components||(b.components=[]);var d=c.points[0],c=c.points[1];b.components.push(new OpenLayers.Bounds(d.x,d.y,c.x,c.y))}},OpenLayers.Format.GML.Base.prototype.readers.gml),feature:OpenLayers.Format.GML.Base.prototype.readers.feature,wfs:OpenLayers.Format.GML.Base.prototype.readers.wfs},write:function(a){var b;b=OpenLayers.Util.isArray(a)?"wfs:FeatureCollection":"gml:featureMember";a=this.writeNode(b,a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);
return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:OpenLayers.Util.applyDefaults({Point:function(a){var b=this.createElementNSPlus("gml:Point");this.writeNode("coordinates",[a],b);return b},coordinates:function(a){for(var b=a.length,c=Array(b),d,e=0;e<b;++e)d=a[e],c[e]=this.xy?d.x+","+d.y:d.y+","+d.x,void 0!=d.z&&(c[e]+=","+d.z);return this.createElementNSPlus("gml:coordinates",{attributes:{decimal:".",cs:",",ts:" "},value:1==b?c[0]:c.join(" ")})},LineString:function(a){var b=
this.createElementNSPlus("gml:LineString");this.writeNode("coordinates",a.components,b);return b},Polygon:function(a){var b=this.createElementNSPlus("gml:Polygon");this.writeNode("outerBoundaryIs",a.components[0],b);for(var c=1;c<a.components.length;++c)this.writeNode("innerBoundaryIs",a.components[c],b);return b},outerBoundaryIs:function(a){var b=this.createElementNSPlus("gml:outerBoundaryIs");this.writeNode("LinearRing",a,b);return b},innerBoundaryIs:function(a){var b=this.createElementNSPlus("gml:innerBoundaryIs");
this.writeNode("LinearRing",a,b);return b},LinearRing:function(a){var b=this.createElementNSPlus("gml:LinearRing");this.writeNode("coordinates",a.components,b);return b},Box:function(a){var b=this.createElementNSPlus("gml:Box");this.writeNode("coordinates",[{x:a.left,y:a.bottom},{x:a.right,y:a.top}],b);this.srsName&&b.setAttribute("srsName",this.srsName);return b}},OpenLayers.Format.GML.Base.prototype.writers.gml),feature:OpenLayers.Format.GML.Base.prototype.writers.feature,wfs:OpenLayers.Format.GML.Base.prototype.writers.wfs},
CLASS_NAME:"OpenLayers.Format.GML.v2"});OpenLayers.Format.Filter.v1_0_0=OpenLayers.Class(OpenLayers.Format.GML.v2,OpenLayers.Format.Filter.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.0.0/filter.xsd",initialize:function(a){OpenLayers.Format.GML.v2.prototype.initialize.apply(this,[a])},readers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsNotEqualTo:function(a,
b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLike:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(a,c);var d=a.getAttribute("wildCard"),e=a.getAttribute("singleChar"),f=a.getAttribute("escape");c.value2regex(d,e,f);b.filters.push(c)}},OpenLayers.Format.Filter.v1.prototype.readers.ogc),gml:OpenLayers.Format.GML.v2.prototype.readers.gml,
feature:OpenLayers.Format.GML.v2.prototype.readers.feature},writers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsNotEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsNotEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLike:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLike",
{attributes:{wildCard:"*",singleChar:".",escape:"!"}});this.writeNode("PropertyName",a,b);this.writeNode("Literal",a.regex2value(),b);return b},BBOX:function(a){var b=this.createElementNSPlus("ogc:BBOX");a.property&&this.writeNode("PropertyName",a,b);var c=this.writeNode("gml:Box",a.value,b);a.projection&&c.setAttribute("srsName",a.projection);return b}},OpenLayers.Format.Filter.v1.prototype.writers.ogc),gml:OpenLayers.Format.GML.v2.prototype.writers.gml,feature:OpenLayers.Format.GML.v2.prototype.writers.feature},
writeSpatial:function(a,b){var c=this.createElementNSPlus("ogc:"+b);this.writeNode("PropertyName",a,c);if(a.value instanceof OpenLayers.Filter.Function)this.writeNode("Function",a.value,c);else{var d;d=a.value instanceof OpenLayers.Geometry?this.writeNode("feature:_geometry",a.value).firstChild:this.writeNode("gml:Box",a.value);a.projection&&d.setAttribute("srsName",a.projection);c.appendChild(d)}return c},CLASS_NAME:"OpenLayers.Format.Filter.v1_0_0"});OpenLayers.Format.WFST.v1_0_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,OpenLayers.Format.WFST.v1,{version:"1.0.0",srsNameInQuery:!1,schemaLocations:{wfs:"http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd"},initialize:function(a){OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this,[a]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[a])},readNode:function(a,b,c){return OpenLayers.Format.GML.v2.prototype.readNode.apply(this,arguments)},readers:{wfs:OpenLayers.Util.applyDefaults({WFS_TransactionResponse:function(a,
b){b.insertIds=[];b.success=!1;this.readChildNodes(a,b)},InsertResult:function(a,b){var c={fids:[]};this.readChildNodes(a,c);b.insertIds=b.insertIds.concat(c.fids)},TransactionResult:function(a,b){this.readChildNodes(a,b)},Status:function(a,b){this.readChildNodes(a,b)},SUCCESS:function(a,b){b.success=!0}},OpenLayers.Format.WFST.v1.prototype.readers.wfs),gml:OpenLayers.Format.GML.v2.prototype.readers.gml,feature:OpenLayers.Format.GML.v2.prototype.readers.feature,ogc:OpenLayers.Format.Filter.v1_0_0.prototype.readers.ogc},
writers:{wfs:OpenLayers.Util.applyDefaults({Query:function(a){a=OpenLayers.Util.extend({featureNS:this.featureNS,featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName,srsNameInQuery:this.srsNameInQuery},a);var b=a.featurePrefix,c=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(b?b+":":"")+a.featureType}});a.srsNameInQuery&&a.srsName&&c.setAttribute("srsName",a.srsName);a.featureNS&&c.setAttribute("xmlns:"+b,a.featureNS);if(a.propertyNames)for(var b=0,d=a.propertyNames.length;b<
d;b++)this.writeNode("ogc:PropertyName",{property:a.propertyNames[b]},c);a.filter&&(this.setFilterProperty(a.filter),this.writeNode("ogc:Filter",a.filter,c));return c}},OpenLayers.Format.WFST.v1.prototype.writers.wfs),gml:OpenLayers.Format.GML.v2.prototype.writers.gml,feature:OpenLayers.Format.GML.v2.prototype.writers.feature,ogc:OpenLayers.Format.Filter.v1_0_0.prototype.writers.ogc},CLASS_NAME:"OpenLayers.Format.WFST.v1_0_0"});OpenLayers.ElementsIndexer=OpenLayers.Class({maxZIndex:null,order:null,indices:null,compare:null,initialize:function(a){this.compare=a?OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER:OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;this.clear()},insert:function(a){this.exists(a)&&this.remove(a);var b=a.id;this.determineZIndex(a);for(var c=-1,d=this.order.length,e;1<d-c;)e=parseInt((c+d)/2),0<this.compare(this,a,OpenLayers.Util.getElement(this.order[e]))?c=e:d=e;this.order.splice(d,
0,b);this.indices[b]=this.getZIndex(a);return this.getNextElement(d)},remove:function(a){a=a.id;var b=OpenLayers.Util.indexOf(this.order,a);0<=b&&(this.order.splice(b,1),delete this.indices[a],this.maxZIndex=0<this.order.length?this.indices[this.order[this.order.length-1]]:0)},clear:function(){this.order=[];this.indices={};this.maxZIndex=0},exists:function(a){return null!=this.indices[a.id]},getZIndex:function(a){return a._style.graphicZIndex},determineZIndex:function(a){var b=a._style.graphicZIndex;
null==b?(b=this.maxZIndex,a._style.graphicZIndex=b):b>this.maxZIndex&&(this.maxZIndex=b)},getNextElement:function(a){a+=1;if(a<this.order.length){var b=OpenLayers.Util.getElement(this.order[a]);void 0==b&&(b=this.getNextElement(a));return b}return null},CLASS_NAME:"OpenLayers.ElementsIndexer"});
OpenLayers.ElementsIndexer.IndexingMethods={Z_ORDER:function(a,b,c){b=a.getZIndex(b);var d=0;c&&(a=a.getZIndex(c),d=b-a);return d},Z_ORDER_DRAWING_ORDER:function(a,b,c){a=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(a,b,c);c&&0==a&&(a=1);return a},Z_ORDER_Y_ORDER:function(a,b,c){a=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(a,b,c);c&&0===a&&(b=c._boundsBottom-b._boundsBottom,a=0===b?1:b);return a}};
OpenLayers.Renderer.Elements=OpenLayers.Class(OpenLayers.Renderer,{rendererRoot:null,root:null,vectorRoot:null,textRoot:null,xmlns:null,xOffset:0,indexer:null,BACKGROUND_ID_SUFFIX:"_background",LABEL_ID_SUFFIX:"_label",LABEL_OUTLINE_SUFFIX:"_outline",initialize:function(a,b){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.rendererRoot=this.createRenderRoot();this.root=this.createRoot("_root");this.vectorRoot=this.createRoot("_vroot");this.textRoot=this.createRoot("_troot");this.root.appendChild(this.vectorRoot);
this.root.appendChild(this.textRoot);this.rendererRoot.appendChild(this.root);this.container.appendChild(this.rendererRoot);b&&(b.zIndexing||b.yOrdering)&&(this.indexer=new OpenLayers.ElementsIndexer(b.yOrdering))},destroy:function(){this.clear();this.xmlns=this.root=this.rendererRoot=null;OpenLayers.Renderer.prototype.destroy.apply(this,arguments)},clear:function(){var a,b=this.vectorRoot;if(b)for(;a=b.firstChild;)b.removeChild(a);if(b=this.textRoot)for(;a=b.firstChild;)b.removeChild(a);this.indexer&&
this.indexer.clear()},setExtent:function(a,b){var c=OpenLayers.Renderer.prototype.setExtent.apply(this,arguments),d=this.getResolution();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var e,f=a.getWidth()/this.map.getExtent().getWidth();a=a.scale(1/f);f=this.map.getMaxExtent();f.right>a.left&&f.right<a.right?e=!0:f.left>a.left&&f.left<a.right&&(e=!1);if(e!==this.rightOfDateLine||b)c=!1,this.xOffset=!0===e?f.getWidth()/d:0;this.rightOfDateLine=e}return c},getNodeType:function(a,b){},drawGeometry:function(a,
b,c){var d=a.CLASS_NAME,e=!0;if("OpenLayers.Geometry.Collection"==d||"OpenLayers.Geometry.MultiPoint"==d||"OpenLayers.Geometry.MultiLineString"==d||"OpenLayers.Geometry.MultiPolygon"==d){for(var d=0,f=a.components.length;d<f;d++)e=this.drawGeometry(a.components[d],b,c)&&e;return e}d=e=!1;"none"!=b.display&&(b.backgroundGraphic?this.redrawBackgroundNode(a.id,a,b,c):d=!0,e=this.redrawNode(a.id,a,b,c));!1==e&&(b=document.getElementById(a.id))&&(b._style.backgroundGraphic&&(d=!0),b.parentNode.removeChild(b));
d&&(b=document.getElementById(a.id+this.BACKGROUND_ID_SUFFIX))&&b.parentNode.removeChild(b);return e},redrawNode:function(a,b,c,d){c=this.applyDefaultSymbolizer(c);a=this.nodeFactory(a,this.getNodeType(b,c));a._featureId=d;a._boundsBottom=b.getBounds().bottom;a._geometryClass=b.CLASS_NAME;a._style=c;b=this.drawGeometryNode(a,b,c);if(!1===b)return!1;a=b.node;this.indexer?(c=this.indexer.insert(a))?this.vectorRoot.insertBefore(a,c):this.vectorRoot.appendChild(a):a.parentNode!==this.vectorRoot&&this.vectorRoot.appendChild(a);
this.postDraw(a);return b.complete},redrawBackgroundNode:function(a,b,c,d){c=OpenLayers.Util.extend({},c);c.externalGraphic=c.backgroundGraphic;c.graphicXOffset=c.backgroundXOffset;c.graphicYOffset=c.backgroundYOffset;c.graphicZIndex=c.backgroundGraphicZIndex;c.graphicWidth=c.backgroundWidth||c.graphicWidth;c.graphicHeight=c.backgroundHeight||c.graphicHeight;c.backgroundGraphic=null;c.backgroundXOffset=null;c.backgroundYOffset=null;c.backgroundGraphicZIndex=null;return this.redrawNode(a+this.BACKGROUND_ID_SUFFIX,
b,c,null)},drawGeometryNode:function(a,b,c){c=c||a._style;var d={isFilled:void 0===c.fill?!0:c.fill,isStroked:void 0===c.stroke?!!c.strokeWidth:c.stroke},e;switch(b.CLASS_NAME){case "OpenLayers.Geometry.Point":!1===c.graphic&&(d.isFilled=!1,d.isStroked=!1);e=this.drawPoint(a,b);break;case "OpenLayers.Geometry.LineString":d.isFilled=!1;e=this.drawLineString(a,b);break;case "OpenLayers.Geometry.LinearRing":e=this.drawLinearRing(a,b);break;case "OpenLayers.Geometry.Polygon":e=this.drawPolygon(a,b);break;
case "OpenLayers.Geometry.Rectangle":e=this.drawRectangle(a,b)}a._options=d;return!1!=e?{node:this.setStyle(a,c,d,b),complete:e}:!1},postDraw:function(a){},drawPoint:function(a,b){},drawLineString:function(a,b){},drawLinearRing:function(a,b){},drawPolygon:function(a,b){},drawRectangle:function(a,b){},drawCircle:function(a,b){},removeText:function(a){var b=document.getElementById(a+this.LABEL_ID_SUFFIX);b&&this.textRoot.removeChild(b);(a=document.getElementById(a+this.LABEL_OUTLINE_SUFFIX))&&this.textRoot.removeChild(a)},
getFeatureIdFromEvent:function(a){var b=a.target,c=b&&b.correspondingUseElement;return(c?c:b||a.srcElement)._featureId},eraseGeometry:function(a,b){if("OpenLayers.Geometry.MultiPoint"==a.CLASS_NAME||"OpenLayers.Geometry.MultiLineString"==a.CLASS_NAME||"OpenLayers.Geometry.MultiPolygon"==a.CLASS_NAME||"OpenLayers.Geometry.Collection"==a.CLASS_NAME)for(var c=0,d=a.components.length;c<d;c++)this.eraseGeometry(a.components[c],b);else(c=OpenLayers.Util.getElement(a.id))&&c.parentNode&&(c.geometry&&(c.geometry.destroy(),
c.geometry=null),c.parentNode.removeChild(c),this.indexer&&this.indexer.remove(c),c._style.backgroundGraphic&&(c=OpenLayers.Util.getElement(a.id+this.BACKGROUND_ID_SUFFIX))&&c.parentNode&&c.parentNode.removeChild(c))},nodeFactory:function(a,b){var c=OpenLayers.Util.getElement(a);c?this.nodeTypeCompare(c,b)||(c.parentNode.removeChild(c),c=this.nodeFactory(a,b)):c=this.createNode(b,a);return c},nodeTypeCompare:function(a,b){},createNode:function(a,b){},moveRoot:function(a){var b=this.root;a.root.parentNode==
this.rendererRoot&&(b=a.root);b.parentNode.removeChild(b);a.rendererRoot.appendChild(b)},getRenderLayerId:function(){return this.root.parentNode.parentNode.id},isComplexSymbol:function(a){return"circle"!=a&&!!a},CLASS_NAME:"OpenLayers.Renderer.Elements"});OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,displayProjection:null,getParameters:function(a){a=a||window.location.href;var b=OpenLayers.Util.getParameters(a),c=a.indexOf("#");0<c&&(a="?"+a.substring(c+1,a.length),OpenLayers.Util.extend(b,OpenLayers.Util.getParameters(a)));return b},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var b=0,c=this.map.controls.length;b<c;b++){var d=this.map.controls[b];if(d!=this&&
"OpenLayers.Control.ArgParser"==d.CLASS_NAME){d.displayProjection!=this.displayProjection&&(this.displayProjection=d.displayProjection);break}}b==this.map.controls.length&&(b=this.getParameters(),b.layers&&(this.layers=b.layers,this.map.events.register("addlayer",this,this.configureLayers),this.configureLayers()),b.lat&&b.lon&&(this.center=new OpenLayers.LonLat(parseFloat(b.lon),parseFloat(b.lat)),b.zoom&&(this.zoom=parseFloat(b.zoom)),this.map.events.register("changebaselayer",this,this.setCenter),
this.setCenter()))},setCenter:function(){this.map.baseLayer&&(this.map.events.unregister("changebaselayer",this,this.setCenter),this.displayProjection&&this.center.transform(this.displayProjection,this.map.getProjectionObject()),this.map.setCenter(this.center,this.zoom))},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister("addlayer",this,this.configureLayers);for(var a=0,b=this.layers.length;a<b;a++){var c=this.map.layers[a],d=this.layers.charAt(a);
"B"==d?this.map.setBaseLayer(c):"T"!=d&&"F"!=d||c.setVisibility("T"==d)}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.Permalink=OpenLayers.Class(OpenLayers.Control,{argParserClass:OpenLayers.Control.ArgParser,element:null,anchor:!1,base:"",displayProjection:null,initialize:function(a,b,c){null===a||"object"!=typeof a||OpenLayers.Util.isElement(a)?(OpenLayers.Control.prototype.initialize.apply(this,[c]),this.element=OpenLayers.Util.getElement(a),this.base=b||document.location.href):(this.base=document.location.href,OpenLayers.Control.prototype.initialize.apply(this,[a]),null!=this.element&&(this.element=
OpenLayers.Util.getElement(this.element)))},destroy:function(){this.element&&this.element.parentNode==this.div&&(this.div.removeChild(this.element),this.element=null);this.map&&this.map.events.unregister("moveend",this,this.updateLink);OpenLayers.Control.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var b=0,c=this.map.controls.length;b<c;b++){var d=this.map.controls[b];if(d.CLASS_NAME==this.argParserClass.CLASS_NAME){d.displayProjection!=
this.displayProjection&&(this.displayProjection=d.displayProjection);break}}b==this.map.controls.length&&this.map.addControl(new this.argParserClass({displayProjection:this.displayProjection}))},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.element||this.anchor||(this.element=document.createElement("a"),this.element.innerHTML=OpenLayers.i18n("Permalink"),this.element.href="",this.div.appendChild(this.element));this.map.events.on({moveend:this.updateLink,changelayer:this.updateLink,
changebaselayer:this.updateLink,scope:this});this.updateLink();return this.div},updateLink:function(){var a=this.anchor?"#":"?",b=this.base,c=null;-1!=b.indexOf("#")&&!1==this.anchor&&(c=b.substring(b.indexOf("#"),b.length));-1!=b.indexOf(a)&&(b=b.substring(0,b.indexOf(a)));b=b.split("#")[0]+a+OpenLayers.Util.getParameterString(this.createParams());c&&(b+=c);this.anchor&&!this.element?window.location.href=b:this.element.href=b},createParams:function(a,b,c){a=a||this.map.getCenter();var d=OpenLayers.Util.getParameters(this.base);
if(a)for(d.zoom=b||this.map.getZoom(),b=a.lat,a=a.lon,this.displayProjection&&(b=OpenLayers.Projection.transform({x:a,y:b},this.map.getProjectionObject(),this.displayProjection),a=b.x,b=b.y),d.lat=Math.round(1E5*b)/1E5,d.lon=Math.round(1E5*a)/1E5,c=c||this.map.layers,d.layers="",a=0,b=c.length;a<b;a++){var e=c[a];d.layers=e.isBaseLayer?d.layers+(e==this.map.baseLayer?"B":"0"):d.layers+(e.getVisibility()?"T":"F")}return d},CLASS_NAME:"OpenLayers.Control.Permalink"});OpenLayers.Layer.TMS=OpenLayers.Class(OpenLayers.Layer.Grid,{serviceVersion:"1.0.0",layername:null,type:null,isBaseLayer:!0,tileOrigin:null,serverResolutions:null,zoomOffset:0,initialize:function(a,b,c){var d=[];d.push(a,b,{},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,d)},clone:function(a){null==a&&(a=new OpenLayers.Layer.TMS(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){a=this.adjustBounds(a);var b=this.getServerResolution(),
c=Math.round((a.left-this.tileOrigin.lon)/(b*this.tileSize.w));a=Math.round((a.bottom-this.tileOrigin.lat)/(b*this.tileSize.h));b=this.getServerZoom();c=this.serviceVersion+"/"+this.layername+"/"+b+"/"+c+"/"+a+"."+this.type;a=this.url;OpenLayers.Util.isArray(a)&&(a=this.selectUrl(c,a));return a+c},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,this.map.maxExtent.bottom))},CLASS_NAME:"OpenLayers.Layer.TMS"});OpenLayers.Format.WCSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.0",CLASS_NAME:"OpenLayers.Format.WCSCapabilities"});OpenLayers.Format.WCSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{regExes:{trimSpace:/^\s*|\s*$/g,splitSpace:/\s+/},defaultPrefix:"wcs",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},CLASS_NAME:"OpenLayers.Format.WCSCapabilities.v1"});OpenLayers.Format.WCSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1,{namespaces:{wcs:"http://www.opengis.net/wcs",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",ows:"http://www.opengis.net/ows"},errorProperty:"service",readers:{wcs:{WCS_Capabilities:function(a,b){this.readChildNodes(a,b)},Service:function(a,b){b.service={};this.readChildNodes(a,b.service)},name:function(a,b){b.name=this.getChildValue(a)},label:function(a,b){b.label=
this.getChildValue(a)},keywords:function(a,b){b.keywords=[];this.readChildNodes(a,b.keywords)},keyword:function(a,b){b.push(this.getChildValue(a))},responsibleParty:function(a,b){b.responsibleParty={};this.readChildNodes(a,b.responsibleParty)},individualName:function(a,b){b.individualName=this.getChildValue(a)},organisationName:function(a,b){b.organisationName=this.getChildValue(a)},positionName:function(a,b){b.positionName=this.getChildValue(a)},contactInfo:function(a,b){b.contactInfo={};this.readChildNodes(a,
b.contactInfo)},phone:function(a,b){b.phone={};this.readChildNodes(a,b.phone)},voice:function(a,b){b.voice=this.getChildValue(a)},facsimile:function(a,b){b.facsimile=this.getChildValue(a)},address:function(a,b){b.address={};this.readChildNodes(a,b.address)},deliveryPoint:function(a,b){b.deliveryPoint=this.getChildValue(a)},city:function(a,b){b.city=this.getChildValue(a)},postalCode:function(a,b){b.postalCode=this.getChildValue(a)},country:function(a,b){b.country=this.getChildValue(a)},electronicMailAddress:function(a,
b){b.electronicMailAddress=this.getChildValue(a)},fees:function(a,b){b.fees=this.getChildValue(a)},accessConstraints:function(a,b){b.accessConstraints=this.getChildValue(a)},ContentMetadata:function(a,b){b.contentMetadata=[];this.readChildNodes(a,b.contentMetadata)},CoverageOfferingBrief:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)},name:function(a,b){b.name=this.getChildValue(a)},label:function(a,b){b.label=this.getChildValue(a)},lonLatEnvelope:function(a,b){var c=this.getElementsByTagNameNS(a,
"http://www.opengis.net/gml","pos");if(2==c.length){var d={},e={};OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this,[c[0],d]);OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this,[c[1],e]);b.lonLatEnvelope={};b.lonLatEnvelope.srsName=a.getAttribute("srsName");b.lonLatEnvelope.min=d.points[0];b.lonLatEnvelope.max=e.points[0]}}}},CLASS_NAME:"OpenLayers.Format.WCSCapabilities.v1_0_0"});OpenLayers.Strategy.Fixed=OpenLayers.Class(OpenLayers.Strategy,{preload:!1,activate:function(){var a=OpenLayers.Strategy.prototype.activate.apply(this,arguments);if(a)if(this.layer.events.on({refresh:this.load,scope:this}),!0==this.layer.visibility||this.preload)this.load();else this.layer.events.on({visibilitychanged:this.load,scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.layer.events.un({refresh:this.load,visibilitychanged:this.load,
scope:this});return a},load:function(a){var b=this.layer;b.events.triggerEvent("loadstart",{filter:b.filter});b.protocol.read(OpenLayers.Util.applyDefaults({callback:this.merge,filter:b.filter,scope:this},a));b.events.un({visibilitychanged:this.load,scope:this})},merge:function(a){var b=this.layer;b.destroyFeatures();var c=a.features;if(c&&0<c.length){var d=b.projection,e=b.map.getProjectionObject();if(!e.equals(d))for(var f,g=0,h=c.length;g<h;++g)(f=c[g].geometry)&&f.transform(d,e);b.addFeatures(c)}b.events.triggerEvent("loadend",
{response:a})},CLASS_NAME:"OpenLayers.Strategy.Fixed"});OpenLayers.Control.Zoom=OpenLayers.Class(OpenLayers.Control,{zoomInText:"+",zoomInId:"olZoomInLink",zoomOutText:"\u2212",zoomOutId:"olZoomOutLink",draw:function(){var a=OpenLayers.Control.prototype.draw.apply(this),b=this.getOrCreateLinks(a),c=b.zoomIn,b=b.zoomOut,d=this.map.events;b.parentNode!==a&&(d=this.events,d.attachToElement(b.parentNode));d.register("buttonclick",this,this.onZoomClick);this.zoomInLink=c;this.zoomOutLink=b;return a},getOrCreateLinks:function(a){var b=document.getElementById(this.zoomInId),
c=document.getElementById(this.zoomOutId);b||(b=document.createElement("a"),b.href="#zoomIn",b.appendChild(document.createTextNode(this.zoomInText)),b.className="olControlZoomIn",a.appendChild(b));OpenLayers.Element.addClass(b,"olButton");c||(c=document.createElement("a"),c.href="#zoomOut",c.appendChild(document.createTextNode(this.zoomOutText)),c.className="olControlZoomOut",a.appendChild(c));OpenLayers.Element.addClass(c,"olButton");return{zoomIn:b,zoomOut:c}},onZoomClick:function(a){a=a.buttonElement;
a===this.zoomInLink?this.map.zoomIn():a===this.zoomOutLink&&this.map.zoomOut()},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onZoomClick);delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this)},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Layer.PointTrack=OpenLayers.Class(OpenLayers.Layer.Vector,{dataFrom:null,styleFrom:null,addNodes:function(a,b){if(2>a.length)throw Error("At least two point features have to be added to create a line from");for(var c=Array(a.length-1),d,e,f,g=0,h=a.length;g<h;g++){d=a[g];f=d.geometry;if(!f)f=d.lonlat,f=new OpenLayers.Geometry.Point(f.lon,f.lat);else if("OpenLayers.Geometry.Point"!=f.CLASS_NAME)throw new TypeError("Only features with point geometries are supported.");if(0<g){d=null!=this.dataFrom?
a[g+this.dataFrom].data||a[g+this.dataFrom].attributes:null;var k=null!=this.styleFrom?a[g+this.styleFrom].style:null;e=new OpenLayers.Geometry.LineString([e,f]);c[g-1]=new OpenLayers.Feature.Vector(e,d,k)}e=f}this.addFeatures(c,b)},CLASS_NAME:"OpenLayers.Layer.PointTrack"});OpenLayers.Layer.PointTrack.SOURCE_NODE=-1;OpenLayers.Layer.PointTrack.TARGET_NODE=0;OpenLayers.Layer.PointTrack.dataFrom={SOURCE_NODE:-1,TARGET_NODE:0};OpenLayers.Protocol.WFS=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.WFS.DEFAULTS);var b=OpenLayers.Protocol.WFS["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported WFS version: "+a.version;return new b(a)};
OpenLayers.Protocol.WFS.fromWMSLayer=function(a,b){var c,d;c=a.params.LAYERS;c=(OpenLayers.Util.isArray(c)?c[0]:c).split(":");1<c.length&&(d=c[0]);c=c.pop();d={url:a.url,featureType:c,featurePrefix:d,srsName:a.projection&&a.projection.getCode()||a.map&&a.map.getProjectionObject().getCode(),version:"1.1.0"};return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(b,d))};OpenLayers.Protocol.WFS.DEFAULTS={version:"1.0.0"};OpenLayers.Layer.Markers=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!1,markers:null,drawn:!1,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.markers=[]},destroy:function(){this.clearMarkers();this.markers=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},setOpacity:function(a){if(a!=this.opacity){this.opacity=a;a=0;for(var b=this.markers.length;a<b;a++)this.markers[a].setOpacity(this.opacity)}},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,
arguments);if(b||!this.drawn){for(var d=0,e=this.markers.length;d<e;d++)this.drawMarker(this.markers[d]);this.drawn=!0}},addMarker:function(a){this.markers.push(a);1>this.opacity&&a.setOpacity(this.opacity);this.map&&this.map.getExtent()&&(a.map=this.map,this.drawMarker(a))},removeMarker:function(a){this.markers&&this.markers.length&&(OpenLayers.Util.removeItem(this.markers,a),a.erase())},clearMarkers:function(){if(null!=this.markers)for(;0<this.markers.length;)this.removeMarker(this.markers[0])},
drawMarker:function(a){var b=this.map.getLayerPxFromLonLat(a.lonlat);null==b?a.display(!1):a.isDrawn()?a.icon&&a.icon.moveTo(b):(a=a.draw(b),this.div.appendChild(a))},getDataExtent:function(){var a=null;if(this.markers&&0<this.markers.length)for(var a=new OpenLayers.Bounds,b=0,c=this.markers.length;b<c;b++)a.extend(this.markers[b].lonlat);return a},CLASS_NAME:"OpenLayers.Layer.Markers"});OpenLayers.Control.Pan=OpenLayers.Class(OpenLayers.Control.Button,{slideFactor:50,slideRatio:null,direction:null,initialize:function(a,b){this.direction=a;this.CLASS_NAME+=this.direction;OpenLayers.Control.prototype.initialize.apply(this,[b])},trigger:function(){if(this.map){var a=OpenLayers.Function.bind(function(a){return this.slideRatio?this.map.getSize()[a]*this.slideRatio:this.slideFactor},this);switch(this.direction){case OpenLayers.Control.Pan.NORTH:this.map.pan(0,-a("h"));break;case OpenLayers.Control.Pan.SOUTH:this.map.pan(0,
a("h"));break;case OpenLayers.Control.Pan.WEST:this.map.pan(-a("w"),0);break;case OpenLayers.Control.Pan.EAST:this.map.pan(a("w"),0)}}},CLASS_NAME:"OpenLayers.Control.Pan"});OpenLayers.Control.Pan.NORTH="North";OpenLayers.Control.Pan.SOUTH="South";OpenLayers.Control.Pan.EAST="East";OpenLayers.Control.Pan.WEST="West";OpenLayers.Format.CSWGetDomain=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.CSWGetDomain.DEFAULTS);var b=OpenLayers.Format.CSWGetDomain["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSWGetDomain version: "+a.version;return new b(a)};OpenLayers.Format.CSWGetDomain.DEFAULTS={version:"2.0.2"};OpenLayers.Format.CSWGetDomain.v2_0_2=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",csw:"http://www.opengis.net/cat/csw/2.0.2"},defaultPrefix:"csw",version:"2.0.2",schemaLocation:"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd",PropertyName:null,ParameterName:null,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==
a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{csw:{GetDomainResponse:function(a,b){this.readChildNodes(a,b)},DomainValues:function(a,b){OpenLayers.Util.isArray(b.DomainValues)||(b.DomainValues=[]);for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;this.readChildNodes(a,d);b.DomainValues.push(d)},PropertyName:function(a,b){b.PropertyName=this.getChildValue(a)},ParameterName:function(a,b){b.ParameterName=this.getChildValue(a)},ListOfValues:function(a,
b){OpenLayers.Util.isArray(b.ListOfValues)||(b.ListOfValues=[]);this.readChildNodes(a,b.ListOfValues)},Value:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.push({Value:d})},ConceptualScheme:function(a,b){b.ConceptualScheme={};this.readChildNodes(a,b.ConceptualScheme)},Name:function(a,b){b.Name=this.getChildValue(a)},Document:function(a,b){b.Document=this.getChildValue(a)},Authority:function(a,b){b.Authority=this.getChildValue(a)},
RangeOfValues:function(a,b){b.RangeOfValues={};this.readChildNodes(a,b.RangeOfValues)},MinValue:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.MinValue=d},MaxValue:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.MaxValue=d}}},write:function(a){a=this.writeNode("csw:GetDomain",a);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{csw:{GetDomain:function(a){var b=
this.createElementNSPlus("csw:GetDomain",{attributes:{service:"CSW",version:this.version}});a.PropertyName||this.PropertyName?this.writeNode("csw:PropertyName",a.PropertyName||this.PropertyName,b):(a.ParameterName||this.ParameterName)&&this.writeNode("csw:ParameterName",a.ParameterName||this.ParameterName,b);this.readChildNodes(b,a);return b},PropertyName:function(a){return this.createElementNSPlus("csw:PropertyName",{value:a})},ParameterName:function(a){return this.createElementNSPlus("csw:ParameterName",
{value:a})}}},CLASS_NAME:"OpenLayers.Format.CSWGetDomain.v2_0_2"});OpenLayers.Format.ArcXML.Features=OpenLayers.Class(OpenLayers.Format.XML,{read:function(a){return(new OpenLayers.Format.ArcXML).read(a).features.feature}});OpenLayers.Control.Snapping=OpenLayers.Class(OpenLayers.Control,{DEFAULTS:{tolerance:10,node:!0,edge:!0,vertex:!0},greedy:!0,precedence:["node","vertex","edge"],resolution:null,geoToleranceCache:null,layer:null,feature:null,point:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.options=a||{};this.options.layer&&this.setLayer(this.options.layer);a=OpenLayers.Util.extend({},this.options.defaults);this.defaults=OpenLayers.Util.applyDefaults(a,this.DEFAULTS);this.setTargets(this.options.targets);
0===this.targets.length&&this.layer&&this.addTargetLayer(this.layer);this.geoToleranceCache={}},setLayer:function(a){this.active?(this.deactivate(),this.layer=a,this.activate()):this.layer=a},setTargets:function(a){this.targets=[];if(a&&a.length)for(var b,c=0,d=a.length;c<d;++c)b=a[c],b instanceof OpenLayers.Layer.Vector?this.addTargetLayer(b):this.addTarget(b)},addTargetLayer:function(a){this.addTarget({layer:a})},addTarget:function(a){a=OpenLayers.Util.applyDefaults(a,this.defaults);a.nodeTolerance=
a.nodeTolerance||a.tolerance;a.vertexTolerance=a.vertexTolerance||a.tolerance;a.edgeTolerance=a.edgeTolerance||a.tolerance;this.targets.push(a)},removeTargetLayer:function(a){for(var b,c=this.targets.length-1;0<=c;--c)b=this.targets[c],b.layer===a&&this.removeTarget(b)},removeTarget:function(a){return OpenLayers.Util.removeItem(this.targets,a)},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a&&this.layer&&this.layer.events)this.layer.events.on({sketchstarted:this.onSketchModified,
sketchmodified:this.onSketchModified,vertexmodified:this.onVertexModified,scope:this});return a},deactivate:function(){var a=OpenLayers.Control.prototype.deactivate.call(this);a&&this.layer&&this.layer.events&&this.layer.events.un({sketchstarted:this.onSketchModified,sketchmodified:this.onSketchModified,vertexmodified:this.onVertexModified,scope:this});this.point=this.feature=null;return a},onSketchModified:function(a){this.feature=a.feature;this.considerSnapping(a.vertex,a.vertex)},onVertexModified:function(a){this.feature=
a.feature;var b=this.layer.map.getLonLatFromViewPortPx(a.pixel);this.considerSnapping(a.vertex,new OpenLayers.Geometry.Point(b.lon,b.lat))},considerSnapping:function(a,b){for(var c={rank:Number.POSITIVE_INFINITY,dist:Number.POSITIVE_INFINITY,x:null,y:null},d=!1,e,f,g=0,h=this.targets.length;g<h;++g)if(f=this.targets[g],e=this.testTarget(f,b))if(this.greedy){c=e;c.target=f;d=!0;break}else if(e.rank<c.rank||e.rank===c.rank&&e.dist<c.dist)c=e,c.target=f,d=!0;d&&(!1!==this.events.triggerEvent("beforesnap",
{point:a,x:c.x,y:c.y,distance:c.dist,layer:c.target.layer,snapType:this.precedence[c.rank]})?(a.x=c.x,a.y=c.y,this.point=a,this.events.triggerEvent("snap",{point:a,snapType:this.precedence[c.rank],layer:c.target.layer,distance:c.dist})):d=!1);this.point&&!d&&(a.x=b.x,a.y=b.y,this.point=null,this.events.triggerEvent("unsnap",{point:a}))},testTarget:function(a,b){var c=this.layer.map.getResolution();if("minResolution"in a&&c<a.minResolution||"maxResolution"in a&&c>=a.maxResolution)return null;for(var c=
{node:this.getGeoTolerance(a.nodeTolerance,c),vertex:this.getGeoTolerance(a.vertexTolerance,c),edge:this.getGeoTolerance(a.edgeTolerance,c)},d=Math.max(c.node,c.vertex,c.edge),e={rank:Number.POSITIVE_INFINITY,dist:Number.POSITIVE_INFINITY},f=!1,g=a.layer.features,h,k,l,m,n,p,q=this.precedence.length,r=new OpenLayers.LonLat(b.x,b.y),s=0,t=g.length;s<t;++s)if(h=g[s],h!==this.feature&&(!h._sketch&&h.state!==OpenLayers.State.DELETE&&(!a.filter||a.filter.evaluate(h)))&&h.atPoint(r,d,d))for(var u=0,v=Math.min(e.rank+
1,q);u<v;++u)if(k=this.precedence[u],a[k])if("edge"===k){if(l=h.geometry.distanceTo(b,{details:!0}),n=l.distance,n<=c[k]&&n<e.dist){e={rank:u,dist:n,x:l.x0,y:l.y0};f=!0;break}}else{l=h.geometry.getVertices("node"===k);p=!1;for(var w=0,x=l.length;w<x;++w)m=l[w],n=m.distanceTo(b),n<=c[k]&&(u<e.rank||u===e.rank&&n<e.dist)&&(e={rank:u,dist:n,x:m.x,y:m.y},p=f=!0);if(p)break}return f?e:null},getGeoTolerance:function(a,b){b!==this.resolution&&(this.resolution=b,this.geoToleranceCache={});var c=this.geoToleranceCache[a];
void 0===c&&(c=a*b,this.geoToleranceCache[a]=c);return c},destroy:function(){this.active&&this.deactivate();delete this.layer;delete this.targets;OpenLayers.Control.prototype.destroy.call(this)},CLASS_NAME:"OpenLayers.Control.Snapping"});OpenLayers.Format.OWSCommon.v1_1_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1,{namespaces:{ows:"http://www.opengis.net/ows/1.1",xlink:"http://www.w3.org/1999/xlink"},readers:{ows:OpenLayers.Util.applyDefaults({ExceptionReport:function(a,b){b.exceptionReport={version:a.getAttribute("version"),language:a.getAttribute("xml:lang"),exceptions:[]};this.readChildNodes(a,b.exceptionReport)},AllowedValues:function(a,b){b.allowedValues={};this.readChildNodes(a,b.allowedValues)},AnyValue:function(a,b){b.anyValue=
!0},DataType:function(a,b){b.dataType=this.getChildValue(a)},Range:function(a,b){b.range={};this.readChildNodes(a,b.range)},MinimumValue:function(a,b){b.minValue=this.getChildValue(a)},MaximumValue:function(a,b){b.maxValue=this.getChildValue(a)},Identifier:function(a,b){b.identifier=this.getChildValue(a)},SupportedCRS:function(a,b){b.supportedCRS=this.getChildValue(a)}},OpenLayers.Format.OWSCommon.v1.prototype.readers.ows)},writers:{ows:OpenLayers.Util.applyDefaults({Range:function(a){var b=this.createElementNSPlus("ows:Range",
{attributes:{"ows:rangeClosure":a.closure}});this.writeNode("ows:MinimumValue",a.minValue,b);this.writeNode("ows:MaximumValue",a.maxValue,b);return b},MinimumValue:function(a){return this.createElementNSPlus("ows:MinimumValue",{value:a})},MaximumValue:function(a){return this.createElementNSPlus("ows:MaximumValue",{value:a})},Value:function(a){return this.createElementNSPlus("ows:Value",{value:a})}},OpenLayers.Format.OWSCommon.v1.prototype.writers.ows)},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1_1_0"});OpenLayers.Format.WCSGetCoverage=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows/1.1",wcs:"http://www.opengis.net/wcs/1.1",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.1.2",schemaLocation:"http://www.opengis.net/wcs/1.1 http://schemas.opengis.net/wcs/1.1/wcsGetCoverage.xsd",write:function(a){a=this.writeNode("wcs:GetCoverage",
a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{wcs:{GetCoverage:function(a){var b=this.createElementNSPlus("wcs:GetCoverage",{attributes:{version:a.version||this.VERSION,service:"WCS"}});this.writeNode("ows:Identifier",a.identifier,b);this.writeNode("wcs:DomainSubset",a.domainSubset,b);this.writeNode("wcs:Output",a.output,b);return b},DomainSubset:function(a){var b=this.createElementNSPlus("wcs:DomainSubset",
{});this.writeNode("ows:BoundingBox",a.boundingBox,b);a.temporalSubset&&this.writeNode("wcs:TemporalSubset",a.temporalSubset,b);return b},TemporalSubset:function(a){for(var b=this.createElementNSPlus("wcs:TemporalSubset",{}),c=0,d=a.timePeriods.length;c<d;++c)this.writeNode("wcs:TimePeriod",a.timePeriods[c],b);return b},TimePeriod:function(a){var b=this.createElementNSPlus("wcs:TimePeriod",{});this.writeNode("wcs:BeginPosition",a.begin,b);this.writeNode("wcs:EndPosition",a.end,b);a.resolution&&this.writeNode("wcs:TimeResolution",
a.resolution,b);return b},BeginPosition:function(a){return this.createElementNSPlus("wcs:BeginPosition",{value:a})},EndPosition:function(a){return this.createElementNSPlus("wcs:EndPosition",{value:a})},TimeResolution:function(a){return this.createElementNSPlus("wcs:TimeResolution",{value:a})},Output:function(a){var b=this.createElementNSPlus("wcs:Output",{attributes:{format:a.format,store:a.store}});a.gridCRS&&this.writeNode("wcs:GridCRS",a.gridCRS,b);return b},GridCRS:function(a){var b=this.createElementNSPlus("wcs:GridCRS",
{});this.writeNode("wcs:GridBaseCRS",a.baseCRS,b);a.type&&this.writeNode("wcs:GridType",a.type,b);a.origin&&this.writeNode("wcs:GridOrigin",a.origin,b);this.writeNode("wcs:GridOffsets",a.offsets,b);a.CS&&this.writeNode("wcs:GridCS",a.CS,b);return b},GridBaseCRS:function(a){return this.createElementNSPlus("wcs:GridBaseCRS",{value:a})},GridOrigin:function(a){return this.createElementNSPlus("wcs:GridOrigin",{value:a})},GridType:function(a){return this.createElementNSPlus("wcs:GridType",{value:a})},GridOffsets:function(a){return this.createElementNSPlus("wcs:GridOffsets",
{value:a})},GridCS:function(a){return this.createElementNSPlus("wcs:GridCS",{value:a})}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.writers.ows},CLASS_NAME:"OpenLayers.Format.WCSGetCoverage"});OpenLayers.Format.KML=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{kml:"http://www.opengis.net/kml/2.2",gx:"http://www.google.com/kml/ext/2.2"},kmlns:"http://earth.google.com/kml/2.0",placemarksDesc:"No description available",foldersName:"OpenLayers export",foldersDesc:"Exported on "+new Date,extractAttributes:!0,kvpAttributes:!1,extractStyles:!1,extractTracks:!1,trackAttributes:null,internalns:null,features:null,styles:null,styleBaseUrl:"",fetched:null,maxDepth:0,initialize:function(a){this.regExes=
{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g,kmlColor:/(\w{2})(\w{2})(\w{2})(\w{2})/,kmlIconPalette:/root:\/\/icons\/palette-(\d+)(\.\w+)/,straightBracket:/\$\[(.*?)\]/g};this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){this.features=[];this.styles={};this.fetched={};return this.parseData(a,{depth:0,styleBaseUrl:this.styleBaseUrl})},parseData:function(a,b){"string"==typeof a&&
(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));for(var c=["Link","NetworkLink","Style","StyleMap","Placemark"],d=0,e=c.length;d<e;++d){var f=c[d],g=this.getElementsByTagNameNS(a,"*",f);if(0!=g.length)switch(f.toLowerCase()){case "link":case "networklink":this.parseLinks(g,b);break;case "style":this.extractStyles&&this.parseStyles(g,b);break;case "stylemap":this.extractStyles&&this.parseStyleMaps(g,b);break;case "placemark":this.parseFeatures(g,b)}}return this.features},parseLinks:function(a,
b){if(b.depth>=this.maxDepth)return!1;var c=OpenLayers.Util.extend({},b);c.depth++;for(var d=0,e=a.length;d<e;d++){var f=this.parseProperty(a[d],"*","href");f&&!this.fetched[f]&&(this.fetched[f]=!0,(f=this.fetchLink(f))&&this.parseData(f,c))}},fetchLink:function(a){if(a=OpenLayers.Request.GET({url:a,async:!1}))return a.responseText},parseStyles:function(a,b){for(var c=0,d=a.length;c<d;c++){var e=this.parseStyle(a[c]);e&&(this.styles[(b.styleBaseUrl||"")+"#"+e.id]=e)}},parseKmlColor:function(a){var b=
null;a&&(a=a.match(this.regExes.kmlColor))&&(b={color:"#"+a[4]+a[3]+a[2],opacity:parseInt(a[1],16)/255});return b},parseStyle:function(a){for(var b={},c=["LineStyle","PolyStyle","IconStyle","BalloonStyle","LabelStyle"],d,e,f=0,g=c.length;f<g;++f)if(d=c[f],e=this.getElementsByTagNameNS(a,"*",d)[0])switch(d.toLowerCase()){case "linestyle":d=this.parseProperty(e,"*","color");if(d=this.parseKmlColor(d))b.strokeColor=d.color,b.strokeOpacity=d.opacity;(d=this.parseProperty(e,"*","width"))&&(b.strokeWidth=
d);break;case "polystyle":d=this.parseProperty(e,"*","color");if(d=this.parseKmlColor(d))b.fillOpacity=d.opacity,b.fillColor=d.color;"0"==this.parseProperty(e,"*","fill")&&(b.fillColor="none");"0"==this.parseProperty(e,"*","outline")&&(b.strokeWidth="0");break;case "iconstyle":var h=parseFloat(this.parseProperty(e,"*","scale")||1);d=32*h;var k=32*h,l=this.getElementsByTagNameNS(e,"*","Icon")[0];if(l){var m=this.parseProperty(l,"*","href");if(m){var n=this.parseProperty(l,"*","w"),p=this.parseProperty(l,
"*","h");!OpenLayers.String.startsWith(m,"http://maps.google.com/mapfiles/kml")||(n||p)||(p=n=64,h/=2);n=n||p;p=p||n;n&&(d=parseInt(n)*h);p&&(k=parseInt(p)*h);if(p=m.match(this.regExes.kmlIconPalette))n=p[1],p=p[2],m=this.parseProperty(l,"*","x"),l=this.parseProperty(l,"*","y"),m="http://maps.google.com/mapfiles/kml/pal"+n+"/icon"+(8*(l?7-l/32:7)+(m?m/32:0))+p;b.graphicOpacity=1;b.externalGraphic=m}}if(e=this.getElementsByTagNameNS(e,"*","hotSpot")[0])m=parseFloat(e.getAttribute("x")),l=parseFloat(e.getAttribute("y")),
n=e.getAttribute("xunits"),"pixels"==n?b.graphicXOffset=-m*h:"insetPixels"==n?b.graphicXOffset=-d+m*h:"fraction"==n&&(b.graphicXOffset=-d*m),e=e.getAttribute("yunits"),"pixels"==e?b.graphicYOffset=-k+l*h+1:"insetPixels"==e?b.graphicYOffset=-(l*h)+1:"fraction"==e&&(b.graphicYOffset=-k*(1-l)+1);b.graphicWidth=d;b.graphicHeight=k;break;case "balloonstyle":(e=OpenLayers.Util.getXmlNodeValue(e))&&(b.balloonStyle=e.replace(this.regExes.straightBracket,"${$1}"));break;case "labelstyle":if(d=this.parseProperty(e,
"*","color"),d=this.parseKmlColor(d))b.fontColor=d.color,b.fontOpacity=d.opacity}!b.strokeColor&&b.fillColor&&(b.strokeColor=b.fillColor);(a=a.getAttribute("id"))&&b&&(b.id=a);return b},parseStyleMaps:function(a,b){for(var c=0,d=a.length;c<d;c++)for(var e=a[c],f=this.getElementsByTagNameNS(e,"*","Pair"),e=e.getAttribute("id"),g=0,h=f.length;g<h;g++){var k=f[g],l=this.parseProperty(k,"*","key");(k=this.parseProperty(k,"*","styleUrl"))&&"normal"==l&&(this.styles[(b.styleBaseUrl||"")+"#"+e]=this.styles[(b.styleBaseUrl||
"")+k])}},parseFeatures:function(a,b){for(var c=[],d=0,e=a.length;d<e;d++){var f=a[d],g=this.parseFeature.apply(this,[f]);if(g){this.extractStyles&&(g.attributes&&g.attributes.styleUrl)&&(g.style=this.getStyle(g.attributes.styleUrl,b));if(this.extractStyles){var h=this.getElementsByTagNameNS(f,"*","Style")[0];h&&(h=this.parseStyle(h))&&(g.style=OpenLayers.Util.extend(g.style,h))}this.extractTracks?(f=this.getElementsByTagNameNS(f,this.namespaces.gx,"Track"))&&0<f.length&&(g={features:[],feature:g},
this.readNode(f[0],g),0<g.features.length&&c.push.apply(c,g.features)):c.push(g)}else throw"Bad Placemark: "+d;}this.features=this.features.concat(c)},readers:{kml:{when:function(a,b){b.whens.push(OpenLayers.Date.parse(this.getChildValue(a)))},_trackPointAttribute:function(a,b){var c=a.nodeName.split(":").pop();b.attributes[c].push(this.getChildValue(a))}},gx:{Track:function(a,b){var c={whens:[],points:[],angles:[]};if(this.trackAttributes){var d;c.attributes={};for(var e=0,f=this.trackAttributes.length;e<
f;++e)d=this.trackAttributes[e],c.attributes[d]=[],d in this.readers.kml||(this.readers.kml[d]=this.readers.kml._trackPointAttribute)}this.readChildNodes(a,c);if(c.whens.length!==c.points.length)throw Error("gx:Track with unequal number of when ("+c.whens.length+") and gx:coord ("+c.points.length+") elements.");var g=0<c.angles.length;if(g&&c.whens.length!==c.angles.length)throw Error("gx:Track with unequal number of when ("+c.whens.length+") and gx:angles ("+c.angles.length+") elements.");for(var h,
e=0,f=c.whens.length;e<f;++e){h=b.feature.clone();h.fid=b.feature.fid||b.feature.id;d=c.points[e];h.geometry=d;"z"in d&&(h.attributes.altitude=d.z);this.internalProjection&&this.externalProjection&&h.geometry.transform(this.externalProjection,this.internalProjection);if(this.trackAttributes)for(var k=0,l=this.trackAttributes.length;k<l;++k)d=this.trackAttributes[k],h.attributes[d]=c.attributes[d][e];h.attributes.when=c.whens[e];h.attributes.trackId=b.feature.id;g&&(d=c.angles[e],h.attributes.heading=
parseFloat(d[0]),h.attributes.tilt=parseFloat(d[1]),h.attributes.roll=parseFloat(d[2]));b.features.push(h)}},coord:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(/\s+/),d=new OpenLayers.Geometry.Point(c[0],c[1]);2<c.length&&(d.z=parseFloat(c[2]));b.points.push(d)},angles:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(/\s+/);b.angles.push(c)}}},parseFeature:function(a){for(var b=["MultiGeometry","Polygon","LineString","Point"],
c,d,e,f=0,g=b.length;f<g;++f)if(c=b[f],this.internalns=a.namespaceURI?a.namespaceURI:this.kmlns,d=this.getElementsByTagNameNS(a,this.internalns,c),0<d.length){if(b=this.parseGeometry[c.toLowerCase()])e=b.apply(this,[d[0]]),this.internalProjection&&this.externalProjection&&e.transform(this.externalProjection,this.internalProjection);else throw new TypeError("Unsupported geometry type: "+c);break}var h;this.extractAttributes&&(h=this.parseAttributes(a));c=new OpenLayers.Feature.Vector(e,h);a=a.getAttribute("id")||
a.getAttribute("name");null!=a&&(c.fid=a);return c},getStyle:function(a,b){var c=OpenLayers.Util.removeTail(a),d=OpenLayers.Util.extend({},b);d.depth++;d.styleBaseUrl=c;!this.styles[a]&&!OpenLayers.String.startsWith(a,"#")&&d.depth<=this.maxDepth&&!this.fetched[c]&&(c=this.fetchLink(c))&&this.parseData(c,d);return OpenLayers.Util.extend({},this.styles[a])},parseGeometry:{point:function(a){var b=this.getElementsByTagNameNS(a,this.internalns,"coordinates");a=[];if(0<b.length){var c=b[0].firstChild.nodeValue,
c=c.replace(this.regExes.removeSpace,"");a=c.split(",")}b=null;if(1<a.length)2==a.length&&(a[2]=null),b=new OpenLayers.Geometry.Point(a[0],a[1],a[2]);else throw"Bad coordinate string: "+c;return b},linestring:function(a,b){var c=this.getElementsByTagNameNS(a,this.internalns,"coordinates"),d=null;if(0<c.length){for(var c=this.getChildValue(c[0]),c=c.replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),d=c.split(this.regExes.splitSpace),e=d.length,f=Array(e),g,h,k=0;k<e;++k)if(g=
d[k].split(","),h=g.length,1<h)2==g.length&&(g[2]=null),f[k]=new OpenLayers.Geometry.Point(g[0],g[1],g[2]);else throw"Bad LineString point coordinates: "+d[k];if(e)d=b?new OpenLayers.Geometry.LinearRing(f):new OpenLayers.Geometry.LineString(f);else throw"Bad LineString coordinates: "+c;}return d},polygon:function(a){a=this.getElementsByTagNameNS(a,this.internalns,"LinearRing");var b=a.length,c=Array(b);if(0<b)for(var d=0,e=a.length;d<e;++d)if(b=this.parseGeometry.linestring.apply(this,[a[d],!0]))c[d]=
b;else throw"Bad LinearRing geometry: "+d;return new OpenLayers.Geometry.Polygon(c)},multigeometry:function(a){for(var b,c=[],d=a.childNodes,e=0,f=d.length;e<f;++e)a=d[e],1==a.nodeType&&(b=a.prefix?a.nodeName.split(":")[1]:a.nodeName,(b=this.parseGeometry[b.toLowerCase()])&&c.push(b.apply(this,[a])));return new OpenLayers.Geometry.Collection(c)}},parseAttributes:function(a){var b={},c=a.getElementsByTagName("ExtendedData");c.length&&(b=this.parseExtendedData(c[0]));var d,e,f;a=a.childNodes;for(var c=
0,g=a.length;c<g;++c)if(d=a[c],1==d.nodeType&&(e=d.childNodes,1<=e.length&&3>=e.length)){switch(e.length){case 1:f=e[0];break;case 2:f=e[0];e=e[1];f=3==f.nodeType||4==f.nodeType?f:e;break;default:f=e[1]}if(3==f.nodeType||4==f.nodeType)if(d=d.prefix?d.nodeName.split(":")[1]:d.nodeName,f=OpenLayers.Util.getXmlNodeValue(f))f=f.replace(this.regExes.trimSpace,""),b[d]=f}return b},parseExtendedData:function(a){var b={},c,d,e,f,g=a.getElementsByTagName("Data");c=0;for(d=g.length;c<d;c++){e=g[c];f=e.getAttribute("name");
var h={},k=e.getElementsByTagName("value");k.length&&(h.value=this.getChildValue(k[0]));this.kvpAttributes?b[f]=h.value:(e=e.getElementsByTagName("displayName"),e.length&&(h.displayName=this.getChildValue(e[0])),b[f]=h)}a=a.getElementsByTagName("SimpleData");c=0;for(d=a.length;c<d;c++)h={},e=a[c],f=e.getAttribute("name"),h.value=this.getChildValue(e),this.kvpAttributes?b[f]=h.value:(h.displayName=f,b[f]=h);return b},parseProperty:function(a,b,c){var d;a=this.getElementsByTagNameNS(a,b,c);try{d=OpenLayers.Util.getXmlNodeValue(a[0])}catch(e){d=
null}return d},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=this.createElementNS(this.kmlns,"kml"),c=this.createFolderXML(),d=0,e=a.length;d<e;++d)c.appendChild(this.createPlacemarkXML(a[d]));b.appendChild(c);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFolderXML:function(){var a=this.createElementNS(this.kmlns,"Folder");if(this.foldersName){var b=this.createElementNS(this.kmlns,"name"),c=this.createTextNode(this.foldersName);b.appendChild(c);a.appendChild(b)}this.foldersDesc&&
(b=this.createElementNS(this.kmlns,"description"),c=this.createTextNode(this.foldersDesc),b.appendChild(c),a.appendChild(b));return a},createPlacemarkXML:function(a){var b=this.createElementNS(this.kmlns,"name"),c=a.style&&a.style.label?a.style.label:a.id;b.appendChild(this.createTextNode(a.attributes.name||c));var d=this.createElementNS(this.kmlns,"description");d.appendChild(this.createTextNode(a.attributes.description||this.placemarksDesc));c=this.createElementNS(this.kmlns,"Placemark");null!=
a.fid&&c.setAttribute("id",a.fid);c.appendChild(b);c.appendChild(d);b=this.buildGeometryNode(a.geometry);c.appendChild(b);a.attributes&&(a=this.buildExtendedData(a.attributes))&&c.appendChild(a);return c},buildGeometryNode:function(a){var b=a.CLASS_NAME,b=b.substring(b.lastIndexOf(".")+1),b=this.buildGeometry[b.toLowerCase()],c=null;b&&(c=b.apply(this,[a]));return c},buildGeometry:{point:function(a){var b=this.createElementNS(this.kmlns,"Point");b.appendChild(this.buildCoordinatesNode(a));return b},
multipoint:function(a){return this.buildGeometry.collection.apply(this,[a])},linestring:function(a){var b=this.createElementNS(this.kmlns,"LineString");b.appendChild(this.buildCoordinatesNode(a));return b},multilinestring:function(a){return this.buildGeometry.collection.apply(this,[a])},linearring:function(a){var b=this.createElementNS(this.kmlns,"LinearRing");b.appendChild(this.buildCoordinatesNode(a));return b},polygon:function(a){var b=this.createElementNS(this.kmlns,"Polygon");a=a.components;
for(var c,d,e=0,f=a.length;e<f;++e)c=0==e?"outerBoundaryIs":"innerBoundaryIs",c=this.createElementNS(this.kmlns,c),d=this.buildGeometry.linearring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},multipolygon:function(a){return this.buildGeometry.collection.apply(this,[a])},collection:function(a){for(var b=this.createElementNS(this.kmlns,"MultiGeometry"),c,d=0,e=a.components.length;d<e;++d)(c=this.buildGeometryNode.apply(this,[a.components[d]]))&&b.appendChild(c);return b}},buildCoordinatesNode:function(a){var b=
this.createElementNS(this.kmlns,"coordinates"),c;if(c=a.components){for(var d=c.length,e=Array(d),f=0;f<d;++f)a=c[f],e[f]=this.buildCoordinates(a);c=e.join(" ")}else c=this.buildCoordinates(a);c=this.createTextNode(c);b.appendChild(c);return b},buildCoordinates:function(a){this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));return a.x+","+a.y},buildExtendedData:function(a){var b=this.createElementNS(this.kmlns,"ExtendedData"),
c;for(c in a)if(a[c]&&"name"!=c&&"description"!=c&&"styleUrl"!=c){var d=this.createElementNS(this.kmlns,"Data");d.setAttribute("name",c);var e=this.createElementNS(this.kmlns,"value");if("object"==typeof a[c]){if(a[c].value&&e.appendChild(this.createTextNode(a[c].value)),a[c].displayName){var f=this.createElementNS(this.kmlns,"displayName");f.appendChild(this.getXMLDoc().createCDATASection(a[c].displayName));d.appendChild(f)}}else e.appendChild(this.createTextNode(a[c]));d.appendChild(e);b.appendChild(d)}return this.isSimpleContent(b)?
null:b},CLASS_NAME:"OpenLayers.Format.KML"});OpenLayers.Format.WMSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.1",profile:null,CLASS_NAME:"OpenLayers.Format.WMSCapabilities"});OpenLayers.Format.WMSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{wms:"http://www.opengis.net/wms",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"wms",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=a;a&&9==a.nodeType&&(a=a.documentElement);var c={};this.readNode(a,c);void 0===c.service&&(a=new OpenLayers.Format.OGCExceptionReport,c.error=a.read(b));return c},readers:{wms:{Service:function(a,
b){b.service={};this.readChildNodes(a,b.service)},Name:function(a,b){b.name=this.getChildValue(a)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b["abstract"]=this.getChildValue(a)},BoundingBox:function(a,b){var c={};c.bbox=[parseFloat(a.getAttribute("minx")),parseFloat(a.getAttribute("miny")),parseFloat(a.getAttribute("maxx")),parseFloat(a.getAttribute("maxy"))];var d={x:parseFloat(a.getAttribute("resx")),y:parseFloat(a.getAttribute("resy"))};isNaN(d.x)&&isNaN(d.y)||(c.res=
d);return c},OnlineResource:function(a,b){b.href=this.getAttributeNS(a,this.namespaces.xlink,"href")},ContactInformation:function(a,b){b.contactInformation={};this.readChildNodes(a,b.contactInformation)},ContactPersonPrimary:function(a,b){b.personPrimary={};this.readChildNodes(a,b.personPrimary)},ContactPerson:function(a,b){b.person=this.getChildValue(a)},ContactOrganization:function(a,b){b.organization=this.getChildValue(a)},ContactPosition:function(a,b){b.position=this.getChildValue(a)},ContactAddress:function(a,
b){b.contactAddress={};this.readChildNodes(a,b.contactAddress)},AddressType:function(a,b){b.type=this.getChildValue(a)},Address:function(a,b){b.address=this.getChildValue(a)},City:function(a,b){b.city=this.getChildValue(a)},StateOrProvince:function(a,b){b.stateOrProvince=this.getChildValue(a)},PostCode:function(a,b){b.postcode=this.getChildValue(a)},Country:function(a,b){b.country=this.getChildValue(a)},ContactVoiceTelephone:function(a,b){b.phone=this.getChildValue(a)},ContactFacsimileTelephone:function(a,
b){b.fax=this.getChildValue(a)},ContactElectronicMailAddress:function(a,b){b.email=this.getChildValue(a)},Fees:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.fees=c)},AccessConstraints:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.accessConstraints=c)},Capability:function(a,b){b.capability={nestedLayers:[],layers:[]};this.readChildNodes(a,b.capability)},Request:function(a,b){b.request={};this.readChildNodes(a,b.request)},GetCapabilities:function(a,
b){b.getcapabilities={formats:[]};this.readChildNodes(a,b.getcapabilities)},Format:function(a,b){OpenLayers.Util.isArray(b.formats)?b.formats.push(this.getChildValue(a)):b.format=this.getChildValue(a)},DCPType:function(a,b){this.readChildNodes(a,b)},HTTP:function(a,b){this.readChildNodes(a,b)},Get:function(a,b){b.get={};this.readChildNodes(a,b.get);b.href||(b.href=b.get.href)},Post:function(a,b){b.post={};this.readChildNodes(a,b.post);b.href||(b.href=b.get.href)},GetMap:function(a,b){b.getmap={formats:[]};
this.readChildNodes(a,b.getmap)},GetFeatureInfo:function(a,b){b.getfeatureinfo={formats:[]};this.readChildNodes(a,b.getfeatureinfo)},Exception:function(a,b){b.exception={formats:[]};this.readChildNodes(a,b.exception)},Layer:function(a,b){var c,d;b.capability?(d=b.capability,c=b):d=b;var e=a.getAttributeNode("queryable"),f=e&&e.specified?a.getAttribute("queryable"):null,g=(e=a.getAttributeNode("cascaded"))&&e.specified?a.getAttribute("cascaded"):null,e=(e=a.getAttributeNode("opaque"))&&e.specified?
a.getAttribute("opaque"):null,h=a.getAttribute("noSubsets"),k=a.getAttribute("fixedWidth"),l=a.getAttribute("fixedHeight"),m=c||{},n=OpenLayers.Util.extend;c={nestedLayers:[],styles:c?[].concat(c.styles):[],srs:c?n({},m.srs):{},metadataURLs:[],bbox:c?n({},m.bbox):{},llbbox:m.llbbox,dimensions:c?n({},m.dimensions):{},authorityURLs:c?n({},m.authorityURLs):{},identifiers:{},keywords:[],queryable:f&&""!==f?"1"===f||"true"===f:m.queryable||!1,cascaded:null!==g?parseInt(g):m.cascaded||0,opaque:e?"1"===
e||"true"===e:m.opaque||!1,noSubsets:null!==h?"1"===h||"true"===h:m.noSubsets||!1,fixedWidth:null!=k?parseInt(k):m.fixedWidth||0,fixedHeight:null!=l?parseInt(l):m.fixedHeight||0,minScale:m.minScale,maxScale:m.maxScale,attribution:m.attribution};b.nestedLayers.push(c);c.capability=d;this.readChildNodes(a,c);delete c.capability;c.name&&(f=c.name.split(":"),g=d.request,e=g.getfeatureinfo,0<f.length&&(c.prefix=f[0]),d.layers.push(c),void 0===c.formats&&(c.formats=g.getmap.formats),void 0===c.infoFormats&&
e&&(c.infoFormats=e.formats))},Attribution:function(a,b){b.attribution={};this.readChildNodes(a,b.attribution)},LogoURL:function(a,b){b.logo={width:a.getAttribute("width"),height:a.getAttribute("height")};this.readChildNodes(a,b.logo)},Style:function(a,b){var c={};b.styles.push(c);this.readChildNodes(a,c)},LegendURL:function(a,b){var c={width:a.getAttribute("width"),height:a.getAttribute("height")};b.legend=c;this.readChildNodes(a,c)},MetadataURL:function(a,b){var c={type:a.getAttribute("type")};
b.metadataURLs.push(c);this.readChildNodes(a,c)},DataURL:function(a,b){b.dataURL={};this.readChildNodes(a,b.dataURL)},FeatureListURL:function(a,b){b.featureListURL={};this.readChildNodes(a,b.featureListURL)},AuthorityURL:function(a,b){var c=a.getAttribute("name"),d={};this.readChildNodes(a,d);b.authorityURLs[c]=d.href},Identifier:function(a,b){var c=a.getAttribute("authority");b.identifiers[c]=this.getChildValue(a)},KeywordList:function(a,b){this.readChildNodes(a,b)},SRS:function(a,b){b.srs[this.getChildValue(a)]=
!0}}},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1"});OpenLayers.Format.WMSCapabilities.v1_1=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1,{readers:{wms:OpenLayers.Util.applyDefaults({WMT_MS_Capabilities:function(a,b){this.readChildNodes(a,b)},Keyword:function(a,b){b.keywords&&b.keywords.push(this.getChildValue(a))},DescribeLayer:function(a,b){b.describelayer={formats:[]};this.readChildNodes(a,b.describelayer)},GetLegendGraphic:function(a,b){b.getlegendgraphic={formats:[]};this.readChildNodes(a,b.getlegendgraphic)},GetStyles:function(a,b){b.getstyles=
{formats:[]};this.readChildNodes(a,b.getstyles)},PutStyles:function(a,b){b.putstyles={formats:[]};this.readChildNodes(a,b.putstyles)},UserDefinedSymbolization:function(a,b){var c={supportSLD:1==parseInt(a.getAttribute("SupportSLD")),userLayer:1==parseInt(a.getAttribute("UserLayer")),userStyle:1==parseInt(a.getAttribute("UserStyle")),remoteWFS:1==parseInt(a.getAttribute("RemoteWFS"))};b.userSymbols=c},LatLonBoundingBox:function(a,b){b.llbbox=[parseFloat(a.getAttribute("minx")),parseFloat(a.getAttribute("miny")),
parseFloat(a.getAttribute("maxx")),parseFloat(a.getAttribute("maxy"))]},BoundingBox:function(a,b){var c=OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms.BoundingBox.apply(this,[a,b]);c.srs=a.getAttribute("SRS");b.bbox[c.srs]=c},ScaleHint:function(a,b){var c=a.getAttribute("min"),d=a.getAttribute("max"),e=Math.pow(2,0.5),f=OpenLayers.INCHES_PER_UNIT.m;0!=c&&(b.maxScale=parseFloat((c/e*f*OpenLayers.DOTS_PER_INCH).toPrecision(13)));d!=Number.POSITIVE_INFINITY&&(b.minScale=parseFloat((d/e*f*
OpenLayers.DOTS_PER_INCH).toPrecision(13)))},Dimension:function(a,b){var c={name:a.getAttribute("name").toLowerCase(),units:a.getAttribute("units"),unitsymbol:a.getAttribute("unitSymbol")};b.dimensions[c.name]=c},Extent:function(a,b){var c=a.getAttribute("name").toLowerCase();if(c in b.dimensions){c=b.dimensions[c];c.nearestVal="1"===a.getAttribute("nearestValue");c.multipleVal="1"===a.getAttribute("multipleValues");c.current="1"===a.getAttribute("current");c["default"]=a.getAttribute("default")||
"";var d=this.getChildValue(a);c.values=d.split(",")}}},OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1"});OpenLayers.Format.WMSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1,{version:"1.1.0",readers:{wms:OpenLayers.Util.applyDefaults({SRS:function(a,b){for(var c=this.getChildValue(a).split(/ +/),d=0,e=c.length;d<e;d++)b.srs[c[d]]=!0}},OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_0"});OpenLayers.Protocol.WFS.v1=OpenLayers.Class(OpenLayers.Protocol,{version:null,srsName:"EPSG:4326",featureType:null,featureNS:null,geometryName:"the_geom",schema:null,featurePrefix:"feature",formatOptions:null,readFormat:null,readOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=OpenLayers.Format.WFST(OpenLayers.Util.extend({version:this.version,featureType:this.featureType,featureNS:this.featureNS,featurePrefix:this.featurePrefix,geometryName:this.geometryName,
srsName:this.srsName,schema:this.schema},this.formatOptions)));!a.geometryName&&1<parseFloat(this.format.version)&&this.setGeometryName(null)},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,this.options||{});var b=new OpenLayers.Protocol.Response({requestType:"read"}),
c=OpenLayers.Format.XML.prototype.write.apply(this.format,[this.format.writeNode("wfs:GetFeature",a)]);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),params:a.params,headers:a.headers,data:c});return b},setFeatureType:function(a){this.featureType=a;this.format.featureType=a},setGeometryName:function(a){this.geometryName=a;this.format.geometryName=a},handleRead:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);if(b.callback){var c=
a.priv;200<=c.status&&300>c.status?(c=this.parseResponse(c,b.readOptions))&&!1!==c.success?(b.readOptions&&"object"==b.readOptions.output?OpenLayers.Util.extend(a,c):a.features=c,a.code=OpenLayers.Protocol.Response.SUCCESS):(a.code=OpenLayers.Protocol.Response.FAILURE,a.error=c):a.code=OpenLayers.Protocol.Response.FAILURE;b.callback.call(b.scope,a)}},parseResponse:function(a,b){var c=a.responseXML;c&&c.documentElement||(c=a.responseText);if(!c||0>=c.length)return null;c=null!==this.readFormat?this.readFormat.read(c):
this.format.read(c,b);if(!this.featureNS){var d=this.readFormat||this.format;this.featureNS=d.featureNS;d.autoConfig=!1;this.geometryName||this.setGeometryName(d.geometryName)}return c},commit:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);var c=new OpenLayers.Protocol.Response({requestType:"commit",reqFeatures:a});c.priv=OpenLayers.Request.POST({url:b.url,headers:b.headers,data:this.format.write(a,b),callback:this.createCallback(this.handleCommit,c,b)});
return c},handleCommit:function(a,b){if(b.callback){var c=a.priv,d=c.responseXML;d&&d.documentElement||(d=c.responseText);c=this.format.read(d)||{};a.insertIds=c.insertIds||[];c.success?a.code=OpenLayers.Protocol.Response.SUCCESS:(a.code=OpenLayers.Protocol.Response.FAILURE,a.error=c);b.callback.call(b.scope,a)}},filterDelete:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);new OpenLayers.Protocol.Response({requestType:"commit"});var c=this.format.createElementNSPlus("wfs:Transaction",
{attributes:{service:"WFS",version:this.version}}),d=this.format.createElementNSPlus("wfs:Delete",{attributes:{typeName:(b.featureNS?this.featurePrefix+":":"")+b.featureType}});b.featureNS&&d.setAttribute("xmlns:"+this.featurePrefix,b.featureNS);var e=this.format.writeNode("ogc:Filter",a);d.appendChild(e);c.appendChild(d);c=OpenLayers.Format.XML.prototype.write.apply(this.format,[c]);return OpenLayers.Request.POST({url:this.url,callback:b.callback||function(){},data:c})},abort:function(a){a&&a.priv.abort()},
CLASS_NAME:"OpenLayers.Protocol.WFS.v1"});OpenLayers.Handler.Feature=OpenLayers.Class(OpenLayers.Handler,{EVENTMAP:{click:{"in":"click",out:"clickout"},mousemove:{"in":"over",out:"out"},dblclick:{"in":"dblclick",out:null},mousedown:{"in":null,out:null},mouseup:{"in":null,out:null},touchstart:{"in":"click",out:"clickout"}},feature:null,lastFeature:null,down:null,up:null,clickTolerance:4,geometryTypes:null,stopClick:!0,stopDown:!0,stopUp:!1,initialize:function(a,b,c,d){OpenLayers.Handler.prototype.initialize.apply(this,[a,c,d]);this.layer=
b},touchstart:function(a){this.startTouch();return OpenLayers.Event.isMultiTouch(a)?!0:this.mousedown(a)},touchmove:function(a){OpenLayers.Event.preventDefault(a)},mousedown:function(a){if(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))this.down=a.xy;return this.handle(a)?!this.stopDown:!0},mouseup:function(a){this.up=a.xy;return this.handle(a)?!this.stopUp:!0},click:function(a){return this.handle(a)?!this.stopClick:!0},mousemove:function(a){if(!this.callbacks.over&&!this.callbacks.out)return!0;
this.handle(a);return!0},dblclick:function(a){return!this.handle(a)},geometryTypeMatches:function(a){return null==this.geometryTypes||-1<OpenLayers.Util.indexOf(this.geometryTypes,a.geometry.CLASS_NAME)},handle:function(a){this.feature&&!this.feature.layer&&(this.feature=null);var b=a.type,c=!1,d=!!this.feature,e="click"==b||"dblclick"==b||"touchstart"==b;(this.feature=this.layer.getFeatureFromEvent(a))&&!this.feature.layer&&(this.feature=null);this.lastFeature&&!this.lastFeature.layer&&(this.lastFeature=
null);this.feature?("touchstart"===b&&OpenLayers.Event.preventDefault(a),a=this.feature!=this.lastFeature,this.geometryTypeMatches(this.feature)?(d&&a?(this.lastFeature&&this.triggerCallback(b,"out",[this.lastFeature]),this.triggerCallback(b,"in",[this.feature])):d&&!e||this.triggerCallback(b,"in",[this.feature]),this.lastFeature=this.feature,c=!0):(this.lastFeature&&(d&&a||e)&&this.triggerCallback(b,"out",[this.lastFeature]),this.feature=null)):this.lastFeature&&(d||e)&&this.triggerCallback(b,"out",
[this.lastFeature]);return c},triggerCallback:function(a,b,c){if(b=this.EVENTMAP[a][b])"click"==a&&this.up&&this.down?(Math.sqrt(Math.pow(this.up.x-this.down.x,2)+Math.pow(this.up.y-this.down.y,2))<=this.clickTolerance&&this.callback(b,c),this.up=this.down=null):this.callback(b,c)},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.moveLayerToTop(),this.map.events.on({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this}),a=!0);
return a},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.moveLayerBack(),this.up=this.down=this.lastFeature=this.feature=null,this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this}),a=!0);return a},handleMapEvents:function(a){"removelayer"!=a.type&&"order"!=a.property||this.moveLayerToTop()},moveLayerToTop:function(){var a=Math.max(this.map.Z_INDEX_BASE.Feature-1,this.layer.getZIndex())+1;this.layer.setZIndex(a)},
moveLayerBack:function(){var a=this.layer.getZIndex()-1;a>=this.map.Z_INDEX_BASE.Feature?this.layer.setZIndex(a):this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer))},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.Layer.Vector.RootContainer=OpenLayers.Class(OpenLayers.Layer.Vector,{displayInLayerSwitcher:!1,layers:null,display:function(){},getFeatureFromEvent:function(a){for(var b=this.layers,c,d=0;d<b.length;d++)if(c=b[d].getFeatureFromEvent(a))return c},setMap:function(a){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);this.collectRoots();a.events.register("changelayer",this,this.handleChangeLayer)},removeMap:function(a){a.events.unregister("changelayer",this,this.handleChangeLayer);
this.resetRoots();OpenLayers.Layer.Vector.prototype.removeMap.apply(this,arguments)},collectRoots:function(){for(var a,b=0;b<this.map.layers.length;++b)a=this.map.layers[b],-1!=OpenLayers.Util.indexOf(this.layers,a)&&a.renderer.moveRoot(this.renderer)},resetRoots:function(){for(var a,b=0;b<this.layers.length;++b)a=this.layers[b],this.renderer&&a.renderer.getRenderLayerId()==this.id&&this.renderer.moveRoot(a.renderer)},handleChangeLayer:function(a){var b=a.layer;"order"==a.property&&-1!=OpenLayers.Util.indexOf(this.layers,
b)&&(this.resetRoots(),this.collectRoots())},CLASS_NAME:"OpenLayers.Layer.Vector.RootContainer"});OpenLayers.Control.SelectFeature=OpenLayers.Class(OpenLayers.Control,{multipleKey:null,toggleKey:null,multiple:!1,clickout:!0,toggle:!1,hover:!1,highlightOnly:!1,box:!1,onBeforeSelect:function(){},onSelect:function(){},onUnselect:function(){},scope:null,geometryTypes:null,layer:null,layers:null,callbacks:null,selectStyle:null,renderIntent:"select",handlers:null,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);null===this.scope&&(this.scope=this);this.initLayer(a);var c=
{click:this.clickFeature,clickout:this.clickoutFeature};this.hover&&(c.over=this.overFeature,c.out=this.outFeature);this.callbacks=OpenLayers.Util.extend(c,this.callbacks);this.handlers={feature:new OpenLayers.Handler.Feature(this,this.layer,this.callbacks,{geometryTypes:this.geometryTypes})};this.box&&(this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},{boxDivClassName:"olHandlerBoxSelectFeature"}))},initLayer:function(a){OpenLayers.Util.isArray(a)?(this.layers=a,this.layer=
new OpenLayers.Layer.Vector.RootContainer(this.id+"_container",{layers:a})):this.layer=a},destroy:function(){this.active&&this.layers&&this.map.removeLayer(this.layer);OpenLayers.Control.prototype.destroy.apply(this,arguments);this.layers&&this.layer.destroy()},activate:function(){this.active||(this.layers&&this.map.addLayer(this.layer),this.handlers.feature.activate(),this.box&&this.handlers.box&&this.handlers.box.activate());return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.active&&
(this.handlers.feature.deactivate(),this.handlers.box&&this.handlers.box.deactivate(),this.layers&&this.map.removeLayer(this.layer));return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},unselectAll:function(a){var b=this.layers||[this.layer],c,d,e,f;for(e=0;e<b.length;++e)if(c=b[e],f=0,null!=c.selectedFeatures)for(;c.selectedFeatures.length>f;)d=c.selectedFeatures[f],a&&a.except==d?++f:this.unselect(d)},clickFeature:function(a){this.hover||(-1<OpenLayers.Util.indexOf(a.layer.selectedFeatures,
a)?this.toggleSelect()?this.unselect(a):this.multipleSelect()||this.unselectAll({except:a}):(this.multipleSelect()||this.unselectAll({except:a}),this.select(a)))},multipleSelect:function(){return this.multiple||this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]},toggleSelect:function(){return this.toggle||this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]},clickoutFeature:function(a){!this.hover&&this.clickout&&this.unselectAll()},overFeature:function(a){var b=
a.layer;this.hover&&(this.highlightOnly?this.highlight(a):-1==OpenLayers.Util.indexOf(b.selectedFeatures,a)&&this.select(a))},outFeature:function(a){if(this.hover)if(this.highlightOnly){if(a._lastHighlighter==this.id)if(a._prevHighlighter&&a._prevHighlighter!=this.id){delete a._lastHighlighter;var b=this.map.getControl(a._prevHighlighter);b&&b.highlight(a)}else this.unhighlight(a)}else this.unselect(a)},highlight:function(a){var b=a.layer;!1!==this.events.triggerEvent("beforefeaturehighlighted",{feature:a})&&
(a._prevHighlighter=a._lastHighlighter,a._lastHighlighter=this.id,b.drawFeature(a,this.selectStyle||this.renderIntent),this.events.triggerEvent("featurehighlighted",{feature:a}))},unhighlight:function(a){var b=a.layer;void 0==a._prevHighlighter?delete a._lastHighlighter:(a._prevHighlighter!=this.id&&(a._lastHighlighter=a._prevHighlighter),delete a._prevHighlighter);b.drawFeature(a,a.style||a.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:a})},select:function(a){var b=
this.onBeforeSelect.call(this.scope,a),c=a.layer;!1!==b&&(b=c.events.triggerEvent("beforefeatureselected",{feature:a}),!1!==b&&(c.selectedFeatures.push(a),this.highlight(a),this.handlers.feature.lastFeature||(this.handlers.feature.lastFeature=c.selectedFeatures[0]),c.events.triggerEvent("featureselected",{feature:a}),this.onSelect.call(this.scope,a)))},unselect:function(a){var b=a.layer;this.unhighlight(a);OpenLayers.Util.removeItem(b.selectedFeatures,a);b.events.triggerEvent("featureunselected",
{feature:a});this.onUnselect.call(this.scope,a)},selectBox:function(a){if(a instanceof OpenLayers.Bounds){var b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom});a=this.map.getLonLatFromPixel({x:a.right,y:a.top});b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat);this.multipleSelect()||this.unselectAll();a=this.multiple;this.multiple=!0;var c=this.layers||[this.layer];this.events.triggerEvent("boxselectionstart",{layers:c});for(var d,e=0;e<c.length;++e){d=c[e];for(var f=0,g=d.features.length;f<g;++f){var h=
d.features[f];h.getVisibility()&&(null==this.geometryTypes||-1<OpenLayers.Util.indexOf(this.geometryTypes,h.geometry.CLASS_NAME))&&b.toGeometry().intersects(h.geometry)&&-1==OpenLayers.Util.indexOf(d.selectedFeatures,h)&&this.select(h)}}this.multiple=a;this.events.triggerEvent("boxselectionend",{layers:c})}},setMap:function(a){this.handlers.feature.setMap(a);this.box&&this.handlers.box.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},setLayer:function(a){var b=this.active;this.unselectAll();
this.deactivate();this.layers&&(this.layer.destroy(),this.layers=null);this.initLayer(a);this.handlers.feature.layer=this.layer;b&&this.activate()},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:!1,citeCompliant:!1,mouseDown:!1,stoppedDown:null,lastDown:null,lastUp:null,persist:!1,stopDown:!1,stopUp:!1,layerOptions:null,pixelTolerance:5,lastTouchPx:null,initialize:function(a,b,c){c&&c.layerOptions&&c.layerOptions.styleMap||(this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{}));OpenLayers.Handler.prototype.initialize.apply(this,arguments)},activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,
arguments))return!1;var a=OpenLayers.Util.extend({displayInLayerSwitcher:!1,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a);this.map.addLayer(this.layer);return!0},createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();
this.layer.addFeatures([this.point],{silent:!0})},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments))return!1;this.cancel();null!=this.layer.map&&(this.destroyFeature(!0),this.layer.destroy(!1));this.layer=null;return!0},destroyFeature:function(a){!this.layer||!a&&this.persist||this.layer.destroyFeatures();this.point=null},destroyPersistedFeature:function(){var a=this.layer;a&&1<a.features.length&&this.layer.features[0].destroy()},finalize:function(a){this.mouseDown=
!1;this.lastTouchPx=this.lastUp=this.lastDown=null;this.callback(a?"cancel":"done",[this.geometryClone()]);this.destroyFeature(a)},cancel:function(){this.finalize(!0)},click:function(a){OpenLayers.Event.stop(a);return!1},dblclick:function(a){OpenLayers.Event.stop(a);return!1},modifyFeature:function(a){this.point||this.createFeature(a);a=this.layer.getLonLatFromViewPortPx(a);this.point.geometry.x=a.lon;this.point.geometry.y=a.lat;this.callback("modify",[this.point.geometry,this.point,!1]);this.point.geometry.clearBounds();
this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.point,this.style)},getGeometry:function(){var a=this.point&&this.point.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiPoint([a]));return a},geometryClone:function(){var a=this.getGeometry();return a&&a.clone()},mousedown:function(a){return this.down(a)},touchstart:function(a){this.startTouch();this.lastTouchPx=a.xy;return this.down(a)},mousemove:function(a){return this.move(a)},touchmove:function(a){this.lastTouchPx=a.xy;
return this.move(a)},mouseup:function(a){return this.up(a)},touchend:function(a){a.xy=this.lastTouchPx;return this.up(a)},down:function(a){this.mouseDown=!0;this.lastDown=a.xy;this.touch||this.modifyFeature(a.xy);this.stoppedDown=this.stopDown;return!this.stopDown},move:function(a){this.touch||this.mouseDown&&!this.stoppedDown||this.modifyFeature(a.xy);return!0},up:function(a){this.mouseDown=!1;this.stoppedDown=this.stopDown;if(!this.checkModifiers(a)||this.lastUp&&this.lastUp.equals(a.xy)||!this.lastDown||
!this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance))return!0;this.touch&&this.modifyFeature(a.xy);this.persist&&this.destroyPersistedFeature();this.lastUp=a.xy;this.finalize();return!this.stopUp},mouseout:function(a){OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv)&&(this.stoppedDown=this.stopDown,this.mouseDown=!1)},passesTolerance:function(a,b,c){var d=!0;null!=c&&a&&b&&a.distanceTo(b)>c&&(d=!1);return d},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,maxVertices:null,doubleTouchTolerance:20,freehand:!1,freehandToggle:"shiftKey",timerId:null,redoStack:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([this.point.geometry]));this.callback("create",[this.point.geometry,this.getSketch()]);
this.point.geometry.clearBounds();this.layer.addFeatures([this.line,this.point],{silent:!0})},destroyFeature:function(a){OpenLayers.Handler.Point.prototype.destroyFeature.call(this,a);this.line=null},destroyPersistedFeature:function(){var a=this.layer;a&&2<a.features.length&&this.layer.features[0].destroy()},removePoint:function(){this.point&&this.layer.removeFeatures([this.point])},addPoint:function(a){this.layer.removeFeatures([this.point]);a=this.layer.getLonLatFromViewPortPx(a);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(a.lon,
a.lat));this.line.geometry.addComponent(this.point.geometry,this.line.geometry.components.length);this.layer.addFeatures([this.point]);this.callback("point",[this.point.geometry,this.getGeometry()]);this.callback("modify",[this.point.geometry,this.getSketch()]);this.drawFeature();delete this.redoStack},insertXY:function(a,b){this.line.geometry.addComponent(new OpenLayers.Geometry.Point(a,b),this.getCurrentPointIndex());this.drawFeature();delete this.redoStack},insertDeltaXY:function(a,b){var c=this.getCurrentPointIndex()-
1,c=this.line.geometry.components[c];!c||(isNaN(c.x)||isNaN(c.y))||this.insertXY(c.x+a,c.y+b)},insertDirectionLength:function(a,b){a*=Math.PI/180;var c=b*Math.cos(a),d=b*Math.sin(a);this.insertDeltaXY(c,d)},insertDeflectionLength:function(a,b){var c=this.getCurrentPointIndex()-1;if(0<c){var d=this.line.geometry.components[c],c=this.line.geometry.components[c-1],d=Math.atan2(d.y-c.y,d.x-c.x);this.insertDirectionLength(180*d/Math.PI+a,b)}},getCurrentPointIndex:function(){return this.line.geometry.components.length-
1},undo:function(){var a=this.line.geometry,b=a.components,c=this.getCurrentPointIndex()-1,d=b[c],e=a.removeComponent(d);e&&(this.touch&&0<c&&(b=a.components,a=b[c-1],c=this.getCurrentPointIndex(),b=b[c],b.x=a.x,b.y=a.y),this.redoStack||(this.redoStack=[]),this.redoStack.push(d),this.drawFeature());return e},redo:function(){var a=this.redoStack&&this.redoStack.pop();a&&(this.line.geometry.addComponent(a,this.getCurrentPointIndex()),this.drawFeature());return!!a},freehandMode:function(a){return this.freehandToggle&&
a[this.freehandToggle]?!this.freehand:this.freehand},modifyFeature:function(a,b){this.line||this.createFeature(a);var c=this.layer.getLonLatFromViewPortPx(a);this.point.geometry.x=c.lon;this.point.geometry.y=c.lat;this.callback("modify",[this.point.geometry,this.getSketch(),b]);this.point.geometry.clearBounds();this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.line,this.style);this.layer.drawFeature(this.point,this.style)},getSketch:function(){return this.line},getGeometry:function(){var a=
this.line&&this.line.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiLineString([a]));return a},touchstart:function(a){if(this.timerId&&this.passesTolerance(this.lastTouchPx,a.xy,this.doubleTouchTolerance))return this.finishGeometry(),window.clearTimeout(this.timerId),this.timerId=null,!1;this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null);this.timerId=window.setTimeout(OpenLayers.Function.bind(function(){this.timerId=null},this),300);return OpenLayers.Handler.Point.prototype.touchstart.call(this,
a)},down:function(a){var b=this.stopDown;this.freehandMode(a)&&(b=!0,this.touch&&(this.modifyFeature(a.xy,!!this.lastUp),OpenLayers.Event.stop(a)));this.touch||this.lastDown&&this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)||this.modifyFeature(a.xy,!!this.lastUp);this.mouseDown=!0;this.lastDown=a.xy;this.stoppedDown=b;return!b},move:function(a){if(this.stoppedDown&&this.freehandMode(a))return this.persist&&this.destroyPersistedFeature(),this.maxVertices&&this.line&&this.line.geometry.components.length===
this.maxVertices?(this.removePoint(),this.finalize()):this.addPoint(a.xy),!1;this.touch||this.mouseDown&&!this.stoppedDown||this.modifyFeature(a.xy,!!this.lastUp);return!0},up:function(a){!this.mouseDown||this.lastUp&&this.lastUp.equals(a.xy)||(this.stoppedDown&&this.freehandMode(a)?(this.persist&&this.destroyPersistedFeature(),this.removePoint(),this.finalize()):this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)&&(this.touch&&this.modifyFeature(a.xy),null==this.lastUp&&this.persist&&this.destroyPersistedFeature(),
this.addPoint(a.xy),this.lastUp=a.xy,this.line.geometry.components.length===this.maxVertices+1&&this.finishGeometry()));this.stoppedDown=this.stopDown;this.mouseDown=!1;return!this.stopUp},finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-1]);this.removePoint();this.finalize()},dblclick:function(a){this.freehandMode(a)||this.finishGeometry();return!1},CLASS_NAME:"OpenLayers.Handler.Path"});OpenLayers.Spherical=OpenLayers.Spherical||{};OpenLayers.Spherical.DEFAULT_RADIUS=6378137;OpenLayers.Spherical.computeDistanceBetween=function(a,b,c){c=c||OpenLayers.Spherical.DEFAULT_RADIUS;var d=Math.sin(Math.PI*(b.lon-a.lon)/360),e=Math.sin(Math.PI*(b.lat-a.lat)/360);a=e*e+d*d*Math.cos(Math.PI*a.lat/180)*Math.cos(Math.PI*b.lat/180);return 2*c*Math.atan2(Math.sqrt(a),Math.sqrt(1-a))};
OpenLayers.Spherical.computeHeading=function(a,b){var c=Math.sin(Math.PI*(a.lon-b.lon)/180)*Math.cos(Math.PI*b.lat/180),d=Math.cos(Math.PI*a.lat/180)*Math.sin(Math.PI*b.lat/180)-Math.sin(Math.PI*a.lat/180)*Math.cos(Math.PI*b.lat/180)*Math.cos(Math.PI*(a.lon-b.lon)/180);return 180*Math.atan2(c,d)/Math.PI};OpenLayers.Control.CacheWrite=OpenLayers.Class(OpenLayers.Control,{layers:null,imageFormat:"image/png",quotaRegEx:/quota/i,setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);var b,c=this.layers||a.layers;for(b=c.length-1;0<=b;--b)this.addLayer({layer:c[b]});if(!this.layers)a.events.on({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this})},addLayer:function(a){a.layer.events.on({tileloadstart:this.makeSameOrigin,tileloaded:this.onTileLoaded,scope:this})},removeLayer:function(a){a.layer.events.un({tileloadstart:this.makeSameOrigin,
tileloaded:this.onTileLoaded,scope:this})},makeSameOrigin:function(a){if(this.active&&(a=a.tile,a instanceof OpenLayers.Tile.Image&&!a.crossOriginKeyword&&"data:"!==a.url.substr(0,5))){var b=OpenLayers.Request.makeSameOrigin(a.url,OpenLayers.ProxyHost);OpenLayers.Control.CacheWrite.urlMap[b]=a.url;a.url=b}},onTileLoaded:function(a){this.active&&(!a.aborted&&a.tile instanceof OpenLayers.Tile.Image&&"data:"!==a.tile.url.substr(0,5))&&(this.cache({tile:a.tile}),delete OpenLayers.Control.CacheWrite.urlMap[a.tile.url])},
cache:function(a){if(window.localStorage){a=a.tile;try{var b=a.getCanvasContext();b&&window.localStorage.setItem("olCache_"+(OpenLayers.Control.CacheWrite.urlMap[a.url]||a.url),b.canvas.toDataURL(this.imageFormat))}catch(c){(b=c.name||c.message)&&this.quotaRegEx.test(b)?this.events.triggerEvent("cachefull",{tile:a}):OpenLayers.Console.error(c.toString())}}},destroy:function(){if(this.layers||this.map){var a,b=this.layers||this.map.layers;for(a=b.length-1;0<=a;--a)this.removeLayer({layer:b[a]})}this.map&&
this.map.events.un({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.CacheWrite"});OpenLayers.Control.CacheWrite.clearCache=function(){if(window.localStorage){var a,b;for(a=window.localStorage.length-1;0<=a;--a)b=window.localStorage.key(a),"olCache_"===b.substr(0,8)&&window.localStorage.removeItem(b)}};OpenLayers.Control.CacheWrite.urlMap={};OpenLayers.Format.Context=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{layerOptions:null,layerParams:null,read:function(a,b){var c=OpenLayers.Format.XML.VersionedOGC.prototype.read.apply(this,arguments);if(b&&b.map)if(this.context=c,b.map instanceof OpenLayers.Map)c=this.mergeContextToMap(c,b.map);else{var d=b.map;if(OpenLayers.Util.isElement(d)||"string"==typeof d)d={div:d};c=this.contextToMap(c,d)}return c},getLayerFromContext:function(a){var b,c,d={queryable:a.queryable,visibility:a.visibility,
maxExtent:a.maxExtent,metadata:OpenLayers.Util.applyDefaults(a.metadata,{styles:a.styles,formats:a.formats,"abstract":a["abstract"],dataURL:a.dataURL}),numZoomLevels:a.numZoomLevels,units:a.units,isBaseLayer:a.isBaseLayer,opacity:a.opacity,displayInLayerSwitcher:a.displayInLayerSwitcher,singleTile:a.singleTile,tileSize:a.tileSize?new OpenLayers.Size(a.tileSize.width,a.tileSize.height):void 0,minScale:a.minScale||a.maxScaleDenominator,maxScale:a.maxScale||a.minScaleDenominator,srs:a.srs,dimensions:a.dimensions,
metadataURL:a.metadataURL};this.layerOptions&&OpenLayers.Util.applyDefaults(d,this.layerOptions);var e={layers:a.name,transparent:a.transparent,version:a.version};if(a.formats&&0<a.formats.length)for(e.format=a.formats[0].value,b=0,c=a.formats.length;b<c;b++){var f=a.formats[b];if(!0==f.current){e.format=f.value;break}}if(a.styles&&0<a.styles.length)for(b=0,c=a.styles.length;b<c;b++)if(f=a.styles[b],!0==f.current){f.href?e.sld=f.href:f.body?e.sld_body=f.body:e.styles=f.name;break}this.layerParams&&
OpenLayers.Util.applyDefaults(e,this.layerParams);b=null;c=a.service;c==OpenLayers.Format.Context.serviceTypes.WFS?(d.strategies=[new OpenLayers.Strategy.BBOX],d.protocol=new OpenLayers.Protocol.WFS({url:a.url,featurePrefix:a.name.split(":")[0],featureType:a.name.split(":").pop()}),b=new OpenLayers.Layer.Vector(a.title||a.name,d)):c==OpenLayers.Format.Context.serviceTypes.KML?(d.strategies=[new OpenLayers.Strategy.Fixed],d.protocol=new OpenLayers.Protocol.HTTP({url:a.url,format:new OpenLayers.Format.KML}),
b=new OpenLayers.Layer.Vector(a.title||a.name,d)):c==OpenLayers.Format.Context.serviceTypes.GML?(d.strategies=[new OpenLayers.Strategy.Fixed],d.protocol=new OpenLayers.Protocol.HTTP({url:a.url,format:new OpenLayers.Format.GML}),b=new OpenLayers.Layer.Vector(a.title||a.name,d)):a.features?(b=new OpenLayers.Layer.Vector(a.title||a.name,d),b.addFeatures(a.features)):!0!==a.categoryLayer&&(b=new OpenLayers.Layer.WMS(a.title||a.name,a.url,e,d));return b},getLayersFromContext:function(a){for(var b=[],c=
0,d=a.length;c<d;c++){var e=this.getLayerFromContext(a[c]);null!==e&&b.push(e)}return b},contextToMap:function(a,b){b=OpenLayers.Util.applyDefaults({maxExtent:a.maxExtent,projection:a.projection,units:a.units},b);b.maxExtent&&(b.maxResolution=b.maxExtent.getWidth()/OpenLayers.Map.TILE_WIDTH);b.metadata={contactInformation:a.contactInformation,"abstract":a["abstract"],keywords:a.keywords,logo:a.logo,descriptionURL:a.descriptionURL};var c=new OpenLayers.Map(b);c.addLayers(this.getLayersFromContext(a.layersContext));
c.setCenter(a.bounds.getCenterLonLat(),c.getZoomForExtent(a.bounds,!0));return c},mergeContextToMap:function(a,b){b.addLayers(this.getLayersFromContext(a.layersContext));return b},write:function(a,b){a=this.toContext(a);return OpenLayers.Format.XML.VersionedOGC.prototype.write.apply(this,arguments)},CLASS_NAME:"OpenLayers.Format.Context"});
OpenLayers.Format.Context.serviceTypes={WMS:"urn:ogc:serviceType:WMS",WFS:"urn:ogc:serviceType:WFS",WCS:"urn:ogc:serviceType:WCS",GML:"urn:ogc:serviceType:GML",SLD:"urn:ogc:serviceType:SLD",FES:"urn:ogc:serviceType:FES",KML:"urn:ogc:serviceType:KML"};OpenLayers.Format.WMC=OpenLayers.Class(OpenLayers.Format.Context,{defaultVersion:"1.1.0",layerToContext:function(a){var b=this.getParser(),c={queryable:a.queryable,visibility:a.visibility,name:a.params.LAYERS,title:a.name,"abstract":a.metadata["abstract"],dataURL:a.metadata.dataURL,metadataURL:a.metadataURL,server:{version:a.params.VERSION,url:a.url},maxExtent:a.maxExtent,transparent:a.params.TRANSPARENT,numZoomLevels:a.numZoomLevels,units:a.units,isBaseLayer:a.isBaseLayer,opacity:1==a.opacity?void 0:
a.opacity,displayInLayerSwitcher:a.displayInLayerSwitcher,singleTile:a.singleTile,tileSize:a.singleTile||!a.tileSize?void 0:{width:a.tileSize.w,height:a.tileSize.h},minScale:a.options.resolutions||a.options.scales||a.options.maxResolution||a.options.minScale?a.minScale:void 0,maxScale:a.options.resolutions||a.options.scales||a.options.minResolution||a.options.maxScale?a.maxScale:void 0,formats:[],styles:[],srs:a.srs,dimensions:a.dimensions};a.metadata.servertitle&&(c.server.title=a.metadata.servertitle);
if(a.metadata.formats&&0<a.metadata.formats.length)for(var d=0,e=a.metadata.formats.length;d<e;d++){var f=a.metadata.formats[d];c.formats.push({value:f.value,current:f.value==a.params.FORMAT})}else c.formats.push({value:a.params.FORMAT,current:!0});if(a.metadata.styles&&0<a.metadata.styles.length)for(d=0,e=a.metadata.styles.length;d<e;d++)b=a.metadata.styles[d],b.current=b.href==a.params.SLD||b.body==a.params.SLD_BODY||b.name==a.params.STYLES?!0:!1,c.styles.push(b);else c.styles.push({href:a.params.SLD,
body:a.params.SLD_BODY,name:a.params.STYLES||b.defaultStyleName,title:b.defaultStyleTitle,current:!0});return c},toContext:function(a){var b={},c=a.layers;if("OpenLayers.Map"==a.CLASS_NAME){var d=a.metadata||{};b.size=a.getSize();b.bounds=a.getExtent();b.projection=a.projection;b.title=a.title;b.keywords=d.keywords;b["abstract"]=d["abstract"];b.logo=d.logo;b.descriptionURL=d.descriptionURL;b.contactInformation=d.contactInformation;b.maxExtent=a.maxExtent}else OpenLayers.Util.applyDefaults(b,a),void 0!=
b.layers&&delete b.layers;void 0==b.layersContext&&(b.layersContext=[]);if(void 0!=c&&OpenLayers.Util.isArray(c))for(a=0,d=c.length;a<d;a++){var e=c[a];e instanceof OpenLayers.Layer.WMS&&b.layersContext.push(this.layerToContext(e))}return b},CLASS_NAME:"OpenLayers.Format.WMC"});OpenLayers.Format.WMC.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ol:"http://openlayers.org/context",wmc:"http://www.opengis.net/context",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"",getNamespacePrefix:function(a){var b=null;if(null==a)b=this.namespaces[this.defaultPrefix];else for(b in this.namespaces)if(this.namespaces[b]==a)break;return b},defaultPrefix:"wmc",rootPrefix:null,defaultStyleName:"",
defaultStyleTitle:"Default",initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a=a.documentElement;this.rootPrefix=a.prefix;var b={version:a.getAttribute("version")};this.runChildNodes(b,a);return b},runChildNodes:function(a,b){for(var c=b.childNodes,d,e,f,g=0,h=c.length;g<h;++g)d=c[g],1==d.nodeType&&(e=this.getNamespacePrefix(d.namespaceURI),f=d.nodeName.split(":").pop(),
(e=this["read_"+e+"_"+f])&&e.apply(this,[a,d]))},read_wmc_General:function(a,b){this.runChildNodes(a,b)},read_wmc_BoundingBox:function(a,b){a.projection=b.getAttribute("SRS");a.bounds=new OpenLayers.Bounds(b.getAttribute("minx"),b.getAttribute("miny"),b.getAttribute("maxx"),b.getAttribute("maxy"))},read_wmc_LayerList:function(a,b){a.layersContext=[];this.runChildNodes(a,b)},read_wmc_Layer:function(a,b){var c={visibility:"1"!=b.getAttribute("hidden"),queryable:"1"==b.getAttribute("queryable"),formats:[],
styles:[],metadata:{}};this.runChildNodes(c,b);a.layersContext.push(c)},read_wmc_Extension:function(a,b){this.runChildNodes(a,b)},read_ol_units:function(a,b){a.units=this.getChildValue(b)},read_ol_maxExtent:function(a,b){var c=new OpenLayers.Bounds(b.getAttribute("minx"),b.getAttribute("miny"),b.getAttribute("maxx"),b.getAttribute("maxy"));a.maxExtent=c},read_ol_transparent:function(a,b){a.transparent=this.getChildValue(b)},read_ol_numZoomLevels:function(a,b){a.numZoomLevels=parseInt(this.getChildValue(b))},
read_ol_opacity:function(a,b){a.opacity=parseFloat(this.getChildValue(b))},read_ol_singleTile:function(a,b){a.singleTile="true"==this.getChildValue(b)},read_ol_tileSize:function(a,b){var c={width:b.getAttribute("width"),height:b.getAttribute("height")};a.tileSize=c},read_ol_isBaseLayer:function(a,b){a.isBaseLayer="true"==this.getChildValue(b)},read_ol_displayInLayerSwitcher:function(a,b){a.displayInLayerSwitcher="true"==this.getChildValue(b)},read_wmc_Server:function(a,b){a.version=b.getAttribute("version");
a.url=this.getOnlineResource_href(b);a.metadata.servertitle=b.getAttribute("title")},read_wmc_FormatList:function(a,b){this.runChildNodes(a,b)},read_wmc_Format:function(a,b){var c={value:this.getChildValue(b)};"1"==b.getAttribute("current")&&(c.current=!0);a.formats.push(c)},read_wmc_StyleList:function(a,b){this.runChildNodes(a,b)},read_wmc_Style:function(a,b){var c={};this.runChildNodes(c,b);"1"==b.getAttribute("current")&&(c.current=!0);a.styles.push(c)},read_wmc_SLD:function(a,b){this.runChildNodes(a,
b)},read_sld_StyledLayerDescriptor:function(a,b){var c=OpenLayers.Format.XML.prototype.write.apply(this,[b]);a.body=c},read_sld_FeatureTypeStyle:function(a,b){var c=OpenLayers.Format.XML.prototype.write.apply(this,[b]);a.body=c},read_wmc_OnlineResource:function(a,b){a.href=this.getAttributeNS(b,this.namespaces.xlink,"href")},read_wmc_Name:function(a,b){var c=this.getChildValue(b);c&&(a.name=c)},read_wmc_Title:function(a,b){var c=this.getChildValue(b);c&&(a.title=c)},read_wmc_MetadataURL:function(a,
b){a.metadataURL=this.getOnlineResource_href(b)},read_wmc_KeywordList:function(a,b){a.keywords=[];this.runChildNodes(a.keywords,b)},read_wmc_Keyword:function(a,b){a.push(this.getChildValue(b))},read_wmc_Abstract:function(a,b){var c=this.getChildValue(b);c&&(a["abstract"]=c)},read_wmc_LogoURL:function(a,b){a.logo={width:b.getAttribute("width"),height:b.getAttribute("height"),format:b.getAttribute("format"),href:this.getOnlineResource_href(b)}},read_wmc_DescriptionURL:function(a,b){a.descriptionURL=
this.getOnlineResource_href(b)},read_wmc_ContactInformation:function(a,b){var c={};this.runChildNodes(c,b);a.contactInformation=c},read_wmc_ContactPersonPrimary:function(a,b){var c={};this.runChildNodes(c,b);a.personPrimary=c},read_wmc_ContactPerson:function(a,b){var c=this.getChildValue(b);c&&(a.person=c)},read_wmc_ContactOrganization:function(a,b){var c=this.getChildValue(b);c&&(a.organization=c)},read_wmc_ContactPosition:function(a,b){var c=this.getChildValue(b);c&&(a.position=c)},read_wmc_ContactAddress:function(a,
b){var c={};this.runChildNodes(c,b);a.contactAddress=c},read_wmc_AddressType:function(a,b){var c=this.getChildValue(b);c&&(a.type=c)},read_wmc_Address:function(a,b){var c=this.getChildValue(b);c&&(a.address=c)},read_wmc_City:function(a,b){var c=this.getChildValue(b);c&&(a.city=c)},read_wmc_StateOrProvince:function(a,b){var c=this.getChildValue(b);c&&(a.stateOrProvince=c)},read_wmc_PostCode:function(a,b){var c=this.getChildValue(b);c&&(a.postcode=c)},read_wmc_Country:function(a,b){var c=this.getChildValue(b);
c&&(a.country=c)},read_wmc_ContactVoiceTelephone:function(a,b){var c=this.getChildValue(b);c&&(a.phone=c)},read_wmc_ContactFacsimileTelephone:function(a,b){var c=this.getChildValue(b);c&&(a.fax=c)},read_wmc_ContactElectronicMailAddress:function(a,b){var c=this.getChildValue(b);c&&(a.email=c)},read_wmc_DataURL:function(a,b){a.dataURL=this.getOnlineResource_href(b)},read_wmc_LegendURL:function(a,b){var c={width:b.getAttribute("width"),height:b.getAttribute("height"),format:b.getAttribute("format"),
href:this.getOnlineResource_href(b)};a.legend=c},read_wmc_DimensionList:function(a,b){a.dimensions={};this.runChildNodes(a.dimensions,b)},read_wmc_Dimension:function(a,b){var c={name:b.getAttribute("name").toLowerCase(),units:b.getAttribute("units")||"",unitSymbol:b.getAttribute("unitSymbol")||"",userValue:b.getAttribute("userValue")||"",nearestValue:"1"===b.getAttribute("nearestValue"),multipleValues:"1"===b.getAttribute("multipleValues"),current:"1"===b.getAttribute("current"),"default":b.getAttribute("default")||
""},d=this.getChildValue(b);c.values=d.split(",");a[c.name]=c},write:function(a,b){var c=this.createElementDefaultNS("ViewContext");this.setAttributes(c,{version:this.VERSION,id:b&&"string"==typeof b.id?b.id:OpenLayers.Util.createUniqueID("OpenLayers_Context_")});this.setAttributeNS(c,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);c.appendChild(this.write_wmc_General(a));c.appendChild(this.write_wmc_LayerList(a));return OpenLayers.Format.XML.prototype.write.apply(this,[c])},createElementDefaultNS:function(a,
b,c){a=this.createElementNS(this.namespaces[this.defaultPrefix],a);b&&a.appendChild(this.createTextNode(b));c&&this.setAttributes(a,c);return a},setAttributes:function(a,b){var c,d;for(d in b)c=b[d].toString(),c.match(/[A-Z]/)?this.setAttributeNS(a,null,d,c):a.setAttribute(d,c)},write_wmc_General:function(a){var b=this.createElementDefaultNS("General");a.size&&b.appendChild(this.createElementDefaultNS("Window",null,{width:a.size.w,height:a.size.h}));var c=a.bounds;b.appendChild(this.createElementDefaultNS("BoundingBox",
null,{minx:c.left.toPrecision(18),miny:c.bottom.toPrecision(18),maxx:c.right.toPrecision(18),maxy:c.top.toPrecision(18),SRS:a.projection}));b.appendChild(this.createElementDefaultNS("Title",a.title));a.keywords&&b.appendChild(this.write_wmc_KeywordList(a.keywords));a["abstract"]&&b.appendChild(this.createElementDefaultNS("Abstract",a["abstract"]));a.logo&&b.appendChild(this.write_wmc_URLType("LogoURL",a.logo.href,a.logo));a.descriptionURL&&b.appendChild(this.write_wmc_URLType("DescriptionURL",a.descriptionURL));
a.contactInformation&&b.appendChild(this.write_wmc_ContactInformation(a.contactInformation));b.appendChild(this.write_ol_MapExtension(a));return b},write_wmc_KeywordList:function(a){for(var b=this.createElementDefaultNS("KeywordList"),c=0,d=a.length;c<d;c++)b.appendChild(this.createElementDefaultNS("Keyword",a[c]));return b},write_wmc_ContactInformation:function(a){var b=this.createElementDefaultNS("ContactInformation");a.personPrimary&&b.appendChild(this.write_wmc_ContactPersonPrimary(a.personPrimary));
a.position&&b.appendChild(this.createElementDefaultNS("ContactPosition",a.position));a.contactAddress&&b.appendChild(this.write_wmc_ContactAddress(a.contactAddress));a.phone&&b.appendChild(this.createElementDefaultNS("ContactVoiceTelephone",a.phone));a.fax&&b.appendChild(this.createElementDefaultNS("ContactFacsimileTelephone",a.fax));a.email&&b.appendChild(this.createElementDefaultNS("ContactElectronicMailAddress",a.email));return b},write_wmc_ContactPersonPrimary:function(a){var b=this.createElementDefaultNS("ContactPersonPrimary");
a.person&&b.appendChild(this.createElementDefaultNS("ContactPerson",a.person));a.organization&&b.appendChild(this.createElementDefaultNS("ContactOrganization",a.organization));return b},write_wmc_ContactAddress:function(a){var b=this.createElementDefaultNS("ContactAddress");a.type&&b.appendChild(this.createElementDefaultNS("AddressType",a.type));a.address&&b.appendChild(this.createElementDefaultNS("Address",a.address));a.city&&b.appendChild(this.createElementDefaultNS("City",a.city));a.stateOrProvince&&
b.appendChild(this.createElementDefaultNS("StateOrProvince",a.stateOrProvince));a.postcode&&b.appendChild(this.createElementDefaultNS("PostCode",a.postcode));a.country&&b.appendChild(this.createElementDefaultNS("Country",a.country));return b},write_ol_MapExtension:function(a){var b=this.createElementDefaultNS("Extension");if(a=a.maxExtent){var c=this.createElementNS(this.namespaces.ol,"ol:maxExtent");this.setAttributes(c,{minx:a.left.toPrecision(18),miny:a.bottom.toPrecision(18),maxx:a.right.toPrecision(18),
maxy:a.top.toPrecision(18)});b.appendChild(c)}return b},write_wmc_LayerList:function(a){for(var b=this.createElementDefaultNS("LayerList"),c=0,d=a.layersContext.length;c<d;++c)b.appendChild(this.write_wmc_Layer(a.layersContext[c]));return b},write_wmc_Layer:function(a){var b=this.createElementDefaultNS("Layer",null,{queryable:a.queryable?"1":"0",hidden:a.visibility?"0":"1"});b.appendChild(this.write_wmc_Server(a));b.appendChild(this.createElementDefaultNS("Name",a.name));b.appendChild(this.createElementDefaultNS("Title",
a.title));a["abstract"]&&b.appendChild(this.createElementDefaultNS("Abstract",a["abstract"]));a.dataURL&&b.appendChild(this.write_wmc_URLType("DataURL",a.dataURL));a.metadataURL&&b.appendChild(this.write_wmc_URLType("MetadataURL",a.metadataURL));return b},write_wmc_LayerExtension:function(a){var b=this.createElementDefaultNS("Extension"),c=a.maxExtent,d=this.createElementNS(this.namespaces.ol,"ol:maxExtent");this.setAttributes(d,{minx:c.left.toPrecision(18),miny:c.bottom.toPrecision(18),maxx:c.right.toPrecision(18),
maxy:c.top.toPrecision(18)});b.appendChild(d);a.tileSize&&!a.singleTile&&(c=this.createElementNS(this.namespaces.ol,"ol:tileSize"),this.setAttributes(c,a.tileSize),b.appendChild(c));for(var c="transparent numZoomLevels units isBaseLayer opacity displayInLayerSwitcher singleTile".split(" "),e=0,f=c.length;e<f;++e)(d=this.createOLPropertyNode(a,c[e]))&&b.appendChild(d);return b},createOLPropertyNode:function(a,b){var c=null;null!=a[b]&&(c=this.createElementNS(this.namespaces.ol,"ol:"+b),c.appendChild(this.createTextNode(a[b].toString())));
return c},write_wmc_Server:function(a){a=a.server;var b=this.createElementDefaultNS("Server"),c={service:"OGC:WMS",version:a.version};a.title&&(c.title=a.title);this.setAttributes(b,c);b.appendChild(this.write_wmc_OnlineResource(a.url));return b},write_wmc_URLType:function(a,b,c){a=this.createElementDefaultNS(a);a.appendChild(this.write_wmc_OnlineResource(b));if(c){b=["width","height","format"];for(var d=0;d<b.length;d++)b[d]in c&&a.setAttribute(b[d],c[b[d]])}return a},write_wmc_DimensionList:function(a){var b=
this.createElementDefaultNS("DimensionList"),c;for(c in a.dimensions){var d={},e=a.dimensions[c],f;for(f in e)d[f]="boolean"==typeof e[f]?Number(e[f]):e[f];e="";d.values&&(e=d.values.join(","),delete d.values);b.appendChild(this.createElementDefaultNS("Dimension",e,d))}return b},write_wmc_FormatList:function(a){for(var b=this.createElementDefaultNS("FormatList"),c=0,d=a.formats.length;c<d;c++){var e=a.formats[c];b.appendChild(this.createElementDefaultNS("Format",e.value,e.current&&!0==e.current?{current:"1"}:
null))}return b},write_wmc_StyleList:function(a){var b=this.createElementDefaultNS("StyleList");if((a=a.styles)&&OpenLayers.Util.isArray(a))for(var c,d=0,e=a.length;d<e;d++){var f=a[d],g=this.createElementDefaultNS("Style",null,f.current&&!0==f.current?{current:"1"}:null);f.href?(c=this.createElementDefaultNS("SLD"),f.name&&c.appendChild(this.createElementDefaultNS("Name",f.name)),f.title&&c.appendChild(this.createElementDefaultNS("Title",f.title)),f.legend&&c.appendChild(this.write_wmc_URLType("LegendURL",
f.legend.href,f.legend)),f=this.write_wmc_OnlineResource(f.href),c.appendChild(f),g.appendChild(c)):f.body?(c=this.createElementDefaultNS("SLD"),f.name&&c.appendChild(this.createElementDefaultNS("Name",f.name)),f.title&&c.appendChild(this.createElementDefaultNS("Title",f.title)),f.legend&&c.appendChild(this.write_wmc_URLType("LegendURL",f.legend.href,f.legend)),f=OpenLayers.Format.XML.prototype.read.apply(this,[f.body]).documentElement,c.ownerDocument&&c.ownerDocument.importNode&&(f=c.ownerDocument.importNode(f,
!0)),c.appendChild(f),g.appendChild(c)):(g.appendChild(this.createElementDefaultNS("Name",f.name)),g.appendChild(this.createElementDefaultNS("Title",f.title)),f["abstract"]&&g.appendChild(this.createElementDefaultNS("Abstract",f["abstract"])),f.legend&&g.appendChild(this.write_wmc_URLType("LegendURL",f.legend.href,f.legend)));b.appendChild(g)}return b},write_wmc_OnlineResource:function(a){var b=this.createElementDefaultNS("OnlineResource");this.setAttributeNS(b,this.namespaces.xlink,"xlink:type",
"simple");this.setAttributeNS(b,this.namespaces.xlink,"xlink:href",a);return b},getOnlineResource_href:function(a){var b={};a=a.getElementsByTagName("OnlineResource");0<a.length&&this.read_wmc_OnlineResource(b,a[0]);return b.href},CLASS_NAME:"OpenLayers.Format.WMC.v1"});OpenLayers.Control.PanPanel=OpenLayers.Class(OpenLayers.Control.Panel,{slideFactor:50,slideRatio:null,initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);a={slideFactor:this.slideFactor,slideRatio:this.slideRatio};this.addControls([new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST,a)])},
CLASS_NAME:"OpenLayers.Control.PanPanel"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",template:"${layers}",destroy:function(){this.map.events.un({removelayer:this.updateAttribution,addlayer:this.updateAttribution,changelayer:this.updateAttribution,changebaselayer:this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({changebaselayer:this.updateAttribution,changelayer:this.updateAttribution,
addlayer:this.updateAttribution,removelayer:this.updateAttribution,scope:this});this.updateAttribution();return this.div},updateAttribution:function(){var a=[];if(this.map&&this.map.layers){for(var b=0,c=this.map.layers.length;b<c;b++){var d=this.map.layers[b];d.attribution&&d.getVisibility()&&-1===OpenLayers.Util.indexOf(a,d.attribution)&&a.push(d.attribution)}this.div.innerHTML=OpenLayers.String.format(this.template,{layers:a.join(this.separator)})}},CLASS_NAME:"OpenLayers.Control.Attribution"});OpenLayers.Kinetic=OpenLayers.Class({threshold:0,deceleration:0.0035,nbPoints:100,delay:200,points:void 0,timerId:void 0,initialize:function(a){OpenLayers.Util.extend(this,a)},begin:function(){OpenLayers.Animation.stop(this.timerId);this.timerId=void 0;this.points=[]},update:function(a){this.points.unshift({xy:a,tick:(new Date).getTime()});this.points.length>this.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;d<e;d++){f=this.points[d];if(c-
f.tick>this.delay)break;b=f}if(b&&(d=(new Date).getTime()-b.tick,c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2)),d=c/d,!(0==d||d<this.threshold)))return c=Math.asin((a.y-b.xy.y)/c),b.xy.x<=a.x&&(c=Math.PI-c),{speed:d,theta:c}},move:function(a,b){var c=a.speed,d=Math.cos(a.theta),e=-Math.sin(a.theta),f=(new Date).getTime(),g=0,h=0;this.timerId=OpenLayers.Animation.start(OpenLayers.Function.bind(function(){if(null!=this.timerId){var a=(new Date).getTime()-f,l=-this.deceleration*Math.pow(a,
2)/2+c*a,m=l*d,l=l*e,n,p;n=!1;0>=-this.deceleration*a+c&&(OpenLayers.Animation.stop(this.timerId),this.timerId=null,n=!0);a=m-g;p=l-h;g=m;h=l;b(a,p,n)}},this))},CLASS_NAME:"OpenLayers.Kinetic"});OpenLayers.Format.WPSExecute=OpenLayers.Class(OpenLayers.Format.XML,OpenLayers.Format.Filter.v1_1_0,{namespaces:{ows:"http://www.opengis.net/ows/1.1",gml:"http://www.opengis.net/gml",wps:"http://www.opengis.net/wps/1.0.0",wfs:"http://www.opengis.net/wfs",ogc:"http://www.opengis.net/ogc",wcs:"http://www.opengis.net/wcs",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.0.0",
schemaLocation:"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd",schemaLocationAttr:function(a){},write:function(a){var b;window.ActiveXObject?this.xmldom=b=new ActiveXObject("Microsoft.XMLDOM"):b=document.implementation.createDocument("","",null);a=this.writeNode("wps:Execute",a,b);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},read:function(a){"string"==typeof a&&(a=
OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},writers:{wps:{Execute:function(a){var b=this.createElementNSPlus("wps:Execute",{attributes:{version:this.VERSION,service:"WPS"}});this.writeNode("ows:Identifier",a.identifier,b);this.writeNode("wps:DataInputs",a.dataInputs,b);this.writeNode("wps:ResponseForm",a.responseForm,b);return b},ResponseForm:function(a){var b=this.createElementNSPlus("wps:ResponseForm",{});a.rawDataOutput&&
this.writeNode("wps:RawDataOutput",a.rawDataOutput,b);a.responseDocument&&this.writeNode("wps:ResponseDocument",a.responseDocument,b);return b},ResponseDocument:function(a){var b=this.createElementNSPlus("wps:ResponseDocument",{attributes:{storeExecuteResponse:a.storeExecuteResponse,lineage:a.lineage,status:a.status}});if(a.outputs)for(var c=0,d=a.outputs.length;c<d;c++)this.writeNode("wps:Output",a.outputs[c],b);return b},Output:function(a){var b=this.createElementNSPlus("wps:Output",{attributes:{asReference:a.asReference,
mimeType:a.mimeType,encoding:a.encoding,schema:a.schema}});this.writeNode("ows:Identifier",a.identifier,b);this.writeNode("ows:Title",a.title,b);this.writeNode("ows:Abstract",a["abstract"],b);return b},RawDataOutput:function(a){var b=this.createElementNSPlus("wps:RawDataOutput",{attributes:{mimeType:a.mimeType,encoding:a.encoding,schema:a.schema}});this.writeNode("ows:Identifier",a.identifier,b);return b},DataInputs:function(a){for(var b=this.createElementNSPlus("wps:DataInputs",{}),c=0,d=a.length;c<
d;++c)this.writeNode("wps:Input",a[c],b);return b},Input:function(a){var b=this.createElementNSPlus("wps:Input",{});this.writeNode("ows:Identifier",a.identifier,b);a.title&&this.writeNode("ows:Title",a.title,b);a.data&&this.writeNode("wps:Data",a.data,b);a.reference&&this.writeNode("wps:Reference",a.reference,b);a.boundingBoxData&&this.writeNode("wps:BoundingBoxData",a.boundingBoxData,b);return b},Data:function(a){var b=this.createElementNSPlus("wps:Data",{});a.literalData?this.writeNode("wps:LiteralData",
a.literalData,b):a.complexData?this.writeNode("wps:ComplexData",a.complexData,b):a.boundingBoxData&&this.writeNode("ows:BoundingBox",a.boundingBoxData,b);return b},LiteralData:function(a){return this.createElementNSPlus("wps:LiteralData",{attributes:{uom:a.uom},value:a.value})},ComplexData:function(a){var b=this.createElementNSPlus("wps:ComplexData",{attributes:{mimeType:a.mimeType,encoding:a.encoding,schema:a.schema}}),c=a.value;"string"===typeof c?b.appendChild(this.getXMLDoc().createCDATASection(a.value)):
b.appendChild(c);return b},Reference:function(a){var b=this.createElementNSPlus("wps:Reference",{attributes:{mimeType:a.mimeType,"xlink:href":a.href,method:a.method,encoding:a.encoding,schema:a.schema}});a.body&&this.writeNode("wps:Body",a.body,b);return b},BoundingBoxData:function(a,b){this.writers.ows.BoundingBox.apply(this,[a,b,"wps:BoundingBoxData"])},Body:function(a){var b=this.createElementNSPlus("wps:Body",{});a.wcs?this.writeNode("wcs:GetCoverage",a.wcs,b):a.wfs?(this.featureType=a.wfs.featureType,
this.version=a.wfs.version,this.writeNode("wfs:GetFeature",a.wfs,b)):this.writeNode("wps:Execute",a,b);return b}},wcs:OpenLayers.Format.WCSGetCoverage.prototype.writers.wcs,wfs:OpenLayers.Format.WFST.v1_1_0.prototype.writers.wfs,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc,ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.writers.ows},readers:{wps:{ExecuteResponse:function(a,b){b.executeResponse={lang:a.getAttribute("lang"),statusLocation:a.getAttribute("statusLocation"),serviceInstance:a.getAttribute("serviceInstance"),
service:a.getAttribute("service")};this.readChildNodes(a,b.executeResponse)},Process:function(a,b){b.process={};this.readChildNodes(a,b.process)},Status:function(a,b){b.status={creationTime:a.getAttribute("creationTime")};this.readChildNodes(a,b.status)},ProcessSucceeded:function(a,b){b.processSucceeded=!0},ProcessOutputs:function(a,b){b.processOutputs=[];this.readChildNodes(a,b.processOutputs)},Output:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)},Reference:function(a,b){b.reference=
{href:a.getAttribute("href"),mimeType:a.getAttribute("mimeType"),encoding:a.getAttribute("encoding"),schema:a.getAttribute("schema")}},Data:function(a,b){b.data={};this.readChildNodes(a,b)},LiteralData:function(a,b){b.literalData={dataType:a.getAttribute("dataType"),uom:a.getAttribute("uom"),value:this.getChildValue(a)}},ComplexData:function(a,b){b.complexData={mimeType:a.getAttribute("mimeType"),schema:a.getAttribute("schema"),encoding:a.getAttribute("encoding"),value:""};if(this.isSimpleContent(a)){var c;
for(c=a.firstChild;c;c=c.nextSibling)switch(c.nodeType){case 3:case 4:b.complexData.value+=c.nodeValue}}else for(c=a.firstChild;c;c=c.nextSibling)1==c.nodeType&&(b.complexData.value=c)},BoundingBox:function(a,b){b.boundingBoxData={dimensions:a.getAttribute("dimensions"),crs:a.getAttribute("crs")};this.readChildNodes(a,b.boundingBoxData)}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WPSExecute"});OpenLayers.Layer.GeoRSS=OpenLayers.Class(OpenLayers.Layer.Markers,{location:null,features:null,formatOptions:null,selectedFeature:null,icon:null,popupSize:null,useFeedTitle:!0,initialize:function(a,b,c){OpenLayers.Layer.Markers.prototype.initialize.apply(this,[a,c]);this.location=b;this.features=[]},destroy:function(){OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);this.clearFeatures();this.features=null},loadRSS:function(){this.loaded||(this.events.triggerEvent("loadstart"),OpenLayers.Request.GET({url:this.location,
success:this.parseData,scope:this}),this.loaded=!0)},moveTo:function(a,b,c){OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);this.visibility&&!this.loaded&&this.loadRSS()},parseData:function(a){var b=a.responseXML;b&&b.documentElement||(b=OpenLayers.Format.XML.prototype.read(a.responseText));if(this.useFeedTitle){a=null;try{a=b.getElementsByTagNameNS("*","title")[0].firstChild.nodeValue}catch(c){a=b.getElementsByTagName("title")[0].firstChild.nodeValue}a&&this.setName(a)}a={};OpenLayers.Util.extend(a,
this.formatOptions);this.map&&!this.projection.equals(this.map.getProjectionObject())&&(a.externalProjection=this.projection,a.internalProjection=this.map.getProjectionObject());b=(new OpenLayers.Format.GeoRSS(a)).read(b);a=0;for(var d=b.length;a<d;a++){var e={},f=b[a];if(f.geometry){var g=f.attributes.title?f.attributes.title:"Untitled",h=f.attributes.description?f.attributes.description:"No description.",k=f.attributes.link?f.attributes.link:"",f=f.geometry.getBounds().getCenterLonLat();e.icon=
null==this.icon?OpenLayers.Marker.defaultIcon():this.icon.clone();e.popupSize=this.popupSize?this.popupSize.clone():new OpenLayers.Size(250,120);if(g||h){e.title=g;e.description=h;var l='<div class="olLayerGeoRSSClose">[x]</div>',l=l+'<div class="olLayerGeoRSSTitle">';k&&(l+='<a class="link" href="'+k+'" target="_blank">');l+=g;k&&(l+="</a>");l+="</div>";l+='<div style="" class="olLayerGeoRSSDescription">';l+=h;l+="</div>";e.popupContentHTML=l}f=new OpenLayers.Feature(this,f,e);this.features.push(f);
e=f.createMarker();e.events.register("click",f,this.markerClick);this.addMarker(e)}}this.events.triggerEvent("loadend")},markerClick:function(a){var b=this==this.layer.selectedFeature;this.layer.selectedFeature=b?null:this;for(var c=0,d=this.layer.map.popups.length;c<d;c++)this.layer.map.removePopup(this.layer.map.popups[c]);b||(b=this.createPopup(),OpenLayers.Event.observe(b.div,"click",OpenLayers.Function.bind(function(){for(var a=0,b=this.layer.map.popups.length;a<b;a++)this.layer.map.removePopup(this.layer.map.popups[a])},
this)),this.layer.map.addPopup(b));OpenLayers.Event.stop(a)},clearFeatures:function(){if(null!=this.features)for(;0<this.features.length;){var a=this.features[0];OpenLayers.Util.removeItem(this.features,a);a.destroy()}},CLASS_NAME:"OpenLayers.Layer.GeoRSS"});OpenLayers.Symbolizer.Point=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Point"});OpenLayers.Symbolizer.Line=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Line"});OpenLayers.Symbolizer.Text=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Text"});OpenLayers.Format.SLD.v1=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,{namespaces:{sld:"http://www.opengis.net/sld",ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"sld",schemaLocation:null,multipleSymbolizers:!1,featureTypeCounter:null,defaultSymbolizer:{fillColor:"#808080",fillOpacity:1,strokeColor:"#000000",strokeOpacity:1,strokeWidth:1,strokeDashstyle:"solid",pointRadius:3,
graphicName:"square"},read:function(a,b){b=OpenLayers.Util.applyDefaults(b,this.options);var c={namedLayers:!0===b.namedLayersAsArray?[]:{}};this.readChildNodes(a,c);return c},readers:OpenLayers.Util.applyDefaults({sld:{StyledLayerDescriptor:function(a,b){b.version=a.getAttribute("version");this.readChildNodes(a,b)},Name:function(a,b){b.name=this.getChildValue(a)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b.description=this.getChildValue(a)},NamedLayer:function(a,b){var c=
{userStyles:[],namedStyles:[]};this.readChildNodes(a,c);for(var d=0,e=c.userStyles.length;d<e;++d)c.userStyles[d].layerName=c.name;OpenLayers.Util.isArray(b.namedLayers)?b.namedLayers.push(c):b.namedLayers[c.name]=c},NamedStyle:function(a,b){b.namedStyles.push(this.getChildName(a.firstChild))},UserStyle:function(a,b){var c={defaultsPerSymbolizer:!0,rules:[]};this.featureTypeCounter=-1;this.readChildNodes(a,c);this.multipleSymbolizers?(delete c.defaultsPerSymbolizer,c=new OpenLayers.Style2(c)):c=new OpenLayers.Style(this.defaultSymbolizer,
c);b.userStyles.push(c)},IsDefault:function(a,b){"1"==this.getChildValue(a)&&(b.isDefault=!0)},FeatureTypeStyle:function(a,b){++this.featureTypeCounter;var c={rules:this.multipleSymbolizers?b.rules:[]};this.readChildNodes(a,c);this.multipleSymbolizers||(b.rules=c.rules)},Rule:function(a,b){var c;this.multipleSymbolizers&&(c={symbolizers:[]});c=new OpenLayers.Rule(c);this.readChildNodes(a,c);b.rules.push(c)},ElseFilter:function(a,b){b.elseFilter=!0},MinScaleDenominator:function(a,b){b.minScaleDenominator=
parseFloat(this.getChildValue(a))},MaxScaleDenominator:function(a,b){b.maxScaleDenominator=parseFloat(this.getChildValue(a))},TextSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Text(c))):b.symbolizer.Text=OpenLayers.Util.applyDefaults(c,b.symbolizer.Text)},LabelPlacement:function(a,b){this.readChildNodes(a,b)},PointPlacement:function(a,b){var c={};this.readChildNodes(a,c);c.labelRotation=
c.rotation;delete c.rotation;var d,e=b.labelAnchorPointX,f=b.labelAnchorPointY;e<=1/3?d="l":e>1/3&&e<2/3?d="c":e>=2/3&&(d="r");f<=1/3?d+="b":f>1/3&&f<2/3?d+="m":f>=2/3&&(d+="t");c.labelAlign=d;OpenLayers.Util.applyDefaults(b,c)},AnchorPoint:function(a,b){this.readChildNodes(a,b)},AnchorPointX:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelAnchorPointX=c)},AnchorPointY:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelAnchorPointY=c)},Displacement:function(a,
b){this.readChildNodes(a,b)},DisplacementX:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelXOffset=c)},DisplacementY:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelYOffset=c)},LinePlacement:function(a,b){this.readChildNodes(a,b)},PerpendicularOffset:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelPerpendicularOffset=c)},Label:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.label=c)},Font:function(a,b){this.readChildNodes(a,
b)},Halo:function(a,b){var c={};this.readChildNodes(a,c);b.haloRadius=c.haloRadius;b.haloColor=c.fillColor;b.haloOpacity=c.fillOpacity},Radius:function(a,b){var c=this.readers.ogc._expression.call(this,a);null!=c&&(b.haloRadius=c)},RasterSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Raster(c))):b.symbolizer.Raster=OpenLayers.Util.applyDefaults(c,b.symbolizer.Raster)},Geometry:function(a,
b){b.geometry={};this.readChildNodes(a,b.geometry)},ColorMap:function(a,b){b.colorMap=[];this.readChildNodes(a,b.colorMap)},ColorMapEntry:function(a,b){var c=a.getAttribute("quantity"),d=a.getAttribute("opacity");b.push({color:a.getAttribute("color"),quantity:null!==c?parseFloat(c):void 0,label:a.getAttribute("label")||void 0,opacity:null!==d?parseFloat(d):void 0})},LineSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Line(c))):
b.symbolizer.Line=OpenLayers.Util.applyDefaults(c,b.symbolizer.Line)},PolygonSymbolizer:function(a,b){var c={fill:!1,stroke:!1};this.multipleSymbolizers||(c=b.symbolizer.Polygon||c);this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Polygon(c))):b.symbolizer.Polygon=c},PointSymbolizer:function(a,b){var c={fill:!1,stroke:!1,graphic:!1};this.multipleSymbolizers||(c=b.symbolizer.Point||c);this.readChildNodes(a,c);this.multipleSymbolizers?
(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Point(c))):b.symbolizer.Point=c},Stroke:function(a,b){b.stroke=!0;this.readChildNodes(a,b)},Fill:function(a,b){b.fill=!0;this.readChildNodes(a,b)},CssParameter:function(a,b){var c=a.getAttribute("name"),d=this.cssMap[c];b.label&&("fill"===c?d="fontColor":"fill-opacity"===c&&(d="fontOpacity"));d&&(c=this.readers.ogc._expression.call(this,a))&&(b[d]=c)},Graphic:function(a,b){b.graphic=!0;var c={};this.readChildNodes(a,c);
for(var d="stroke strokeColor strokeWidth strokeOpacity strokeLinecap fill fillColor fillOpacity graphicName rotation graphicFormat".split(" "),e,f,g=0,h=d.length;g<h;++g)e=d[g],f=c[e],void 0!=f&&(b[e]=f);void 0!=c.opacity&&(b.graphicOpacity=c.opacity);void 0!=c.size&&(isNaN(c.size/2)?b.graphicWidth=c.size:b.pointRadius=c.size/2);void 0!=c.href&&(b.externalGraphic=c.href);void 0!=c.rotation&&(b.rotation=c.rotation)},ExternalGraphic:function(a,b){this.readChildNodes(a,b)},Mark:function(a,b){this.readChildNodes(a,
b)},WellKnownName:function(a,b){b.graphicName=this.getChildValue(a)},Opacity:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.opacity=c)},Size:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.size=c)},Rotation:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.rotation=c)},OnlineResource:function(a,b){b.href=this.getAttributeNS(a,this.namespaces.xlink,"href")},Format:function(a,b){b.graphicFormat=this.getChildValue(a)}}},OpenLayers.Format.Filter.v1_0_0.prototype.readers),
cssMap:{stroke:"strokeColor","stroke-opacity":"strokeOpacity","stroke-width":"strokeWidth","stroke-linecap":"strokeLinecap","stroke-dasharray":"strokeDashstyle",fill:"fillColor","fill-opacity":"fillOpacity","font-family":"fontFamily","font-size":"fontSize","font-weight":"fontWeight","font-style":"fontStyle"},getCssProperty:function(a){var b=null,c;for(c in this.cssMap)if(this.cssMap[c]==a){b=c;break}return b},getGraphicFormat:function(a){var b,c;for(c in this.graphicFormats)if(this.graphicFormats[c].test(a)){b=
c;break}return b||this.defaultGraphicFormat},defaultGraphicFormat:"image/png",graphicFormats:{"image/jpeg":/\.jpe?g$/i,"image/gif":/\.gif$/i,"image/png":/\.png$/i},write:function(a){return this.writers.sld.StyledLayerDescriptor.apply(this,[a])},writers:OpenLayers.Util.applyDefaults({sld:{_OGCExpression:function(a,b){var c=this.createElementNSPlus(a),d="string"==typeof b?b.split("${"):[b];c.appendChild(this.createTextNode(d[0]));for(var e,f,g=1,h=d.length;g<h;g++)e=d[g],f=e.indexOf("}"),0<f?(this.writeNode("ogc:PropertyName",
{property:e.substring(0,f)},c),c.appendChild(this.createTextNode(e.substring(++f)))):c.appendChild(this.createTextNode("${"+e));return c},StyledLayerDescriptor:function(a){var b=this.createElementNSPlus("sld:StyledLayerDescriptor",{attributes:{version:this.VERSION,"xsi:schemaLocation":this.schemaLocation}});b.setAttribute("xmlns:ogc",this.namespaces.ogc);b.setAttribute("xmlns:gml",this.namespaces.gml);a.name&&this.writeNode("Name",a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&
this.writeNode("Abstract",a.description,b);if(OpenLayers.Util.isArray(a.namedLayers))for(var c=0,d=a.namedLayers.length;c<d;++c)this.writeNode("NamedLayer",a.namedLayers[c],b);else for(c in a.namedLayers)this.writeNode("NamedLayer",a.namedLayers[c],b);return b},Name:function(a){return this.createElementNSPlus("sld:Name",{value:a})},Title:function(a){return this.createElementNSPlus("sld:Title",{value:a})},Abstract:function(a){return this.createElementNSPlus("sld:Abstract",{value:a})},NamedLayer:function(a){var b=
this.createElementNSPlus("sld:NamedLayer");this.writeNode("Name",a.name,b);if(a.namedStyles)for(var c=0,d=a.namedStyles.length;c<d;++c)this.writeNode("NamedStyle",a.namedStyles[c],b);if(a.userStyles)for(c=0,d=a.userStyles.length;c<d;++c)this.writeNode("UserStyle",a.userStyles[c],b);return b},NamedStyle:function(a){var b=this.createElementNSPlus("sld:NamedStyle");this.writeNode("Name",a,b);return b},UserStyle:function(a){var b=this.createElementNSPlus("sld:UserStyle");a.name&&this.writeNode("Name",
a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&this.writeNode("Abstract",a.description,b);a.isDefault&&this.writeNode("IsDefault",a.isDefault,b);if(this.multipleSymbolizers&&a.rules){for(var c={0:[]},d=[0],e,f,g,h,k,l=0,m=a.rules.length;l<m;++l)if(e=a.rules[l],e.symbolizers){f={};for(var n=0,p=e.symbolizers.length;n<p;++n)g=e.symbolizers[n],h=g.zIndex,h in f||(k=e.clone(),k.symbolizers=[],f[h]=k),f[h].symbolizers.push(g.clone());for(h in f)h in c||(d.push(h),c[h]=[]),c[h].push(f[h])}else c[0].push(e.clone());
d.sort();l=0;for(m=d.length;l<m;++l)e=c[d[l]],0<e.length&&(k=a.clone(),k.rules=c[d[l]],this.writeNode("FeatureTypeStyle",k,b))}else this.writeNode("FeatureTypeStyle",a,b);return b},IsDefault:function(a){return this.createElementNSPlus("sld:IsDefault",{value:a?"1":"0"})},FeatureTypeStyle:function(a){for(var b=this.createElementNSPlus("sld:FeatureTypeStyle"),c=0,d=a.rules.length;c<d;++c)this.writeNode("Rule",a.rules[c],b);return b},Rule:function(a){var b=this.createElementNSPlus("sld:Rule");a.name&&
this.writeNode("Name",a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&this.writeNode("Abstract",a.description,b);a.elseFilter?this.writeNode("ElseFilter",null,b):a.filter&&this.writeNode("ogc:Filter",a.filter,b);void 0!=a.minScaleDenominator&&this.writeNode("MinScaleDenominator",a.minScaleDenominator,b);void 0!=a.maxScaleDenominator&&this.writeNode("MaxScaleDenominator",a.maxScaleDenominator,b);var c,d;if(this.multipleSymbolizers&&a.symbolizers)for(var e=0,f=a.symbolizers.length;e<
f;++e)d=a.symbolizers[e],c=d.CLASS_NAME.split(".").pop(),this.writeNode(c+"Symbolizer",d,b);else for(var f=OpenLayers.Style.SYMBOLIZER_PREFIXES,e=0,g=f.length;e<g;++e)c=f[e],(d=a.symbolizer[c])&&this.writeNode(c+"Symbolizer",d,b);return b},ElseFilter:function(){return this.createElementNSPlus("sld:ElseFilter")},MinScaleDenominator:function(a){return this.createElementNSPlus("sld:MinScaleDenominator",{value:a})},MaxScaleDenominator:function(a){return this.createElementNSPlus("sld:MaxScaleDenominator",
{value:a})},LineSymbolizer:function(a){var b=this.createElementNSPlus("sld:LineSymbolizer");this.writeNode("Stroke",a,b);return b},Stroke:function(a){var b=this.createElementNSPlus("sld:Stroke");void 0!=a.strokeColor&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeColor"},b);void 0!=a.strokeOpacity&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeOpacity"},b);void 0!=a.strokeWidth&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeWidth"},b);void 0!=a.strokeDashstyle&&"solid"!==
a.strokeDashstyle&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeDashstyle"},b);void 0!=a.strokeLinecap&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeLinecap"},b);return b},CssParameter:function(a){return this.createElementNSPlus("sld:CssParameter",{attributes:{name:this.getCssProperty(a.key)},value:a.symbolizer[a.key]})},TextSymbolizer:function(a){var b=this.createElementNSPlus("sld:TextSymbolizer");null!=a.label&&this.writeNode("Label",a.label,b);null==a.fontFamily&&null==a.fontSize&&
null==a.fontWeight&&null==a.fontStyle||this.writeNode("Font",a,b);null==a.labelAnchorPointX&&null==a.labelAnchorPointY&&null==a.labelAlign&&null==a.labelXOffset&&null==a.labelYOffset&&null==a.labelRotation&&null==a.labelPerpendicularOffset||this.writeNode("LabelPlacement",a,b);null==a.haloRadius&&null==a.haloColor&&null==a.haloOpacity||this.writeNode("Halo",a,b);null==a.fontColor&&null==a.fontOpacity||this.writeNode("Fill",{fillColor:a.fontColor,fillOpacity:a.fontOpacity},b);return b},LabelPlacement:function(a){var b=
this.createElementNSPlus("sld:LabelPlacement");null==a.labelAnchorPointX&&null==a.labelAnchorPointY&&null==a.labelAlign&&null==a.labelXOffset&&null==a.labelYOffset&&null==a.labelRotation||null!=a.labelPerpendicularOffset||this.writeNode("PointPlacement",a,b);null!=a.labelPerpendicularOffset&&this.writeNode("LinePlacement",a,b);return b},LinePlacement:function(a){var b=this.createElementNSPlus("sld:LinePlacement");this.writeNode("PerpendicularOffset",a.labelPerpendicularOffset,b);return b},PerpendicularOffset:function(a){return this.createElementNSPlus("sld:PerpendicularOffset",
{value:a})},PointPlacement:function(a){var b=this.createElementNSPlus("sld:PointPlacement");null==a.labelAnchorPointX&&null==a.labelAnchorPointY&&null==a.labelAlign||this.writeNode("AnchorPoint",a,b);null==a.labelXOffset&&null==a.labelYOffset||this.writeNode("Displacement",a,b);null!=a.labelRotation&&this.writeNode("Rotation",a.labelRotation,b);return b},AnchorPoint:function(a){var b=this.createElementNSPlus("sld:AnchorPoint"),c=a.labelAnchorPointX,d=a.labelAnchorPointY;null!=c&&this.writeNode("AnchorPointX",
c,b);null!=d&&this.writeNode("AnchorPointY",d,b);if(null==c&&null==d){var e=a.labelAlign.substr(0,1);a=a.labelAlign.substr(1,1);"l"===e?c=0:"c"===e?c=0.5:"r"===e&&(c=1);"b"===a?d=0:"m"===a?d=0.5:"t"===a&&(d=1);this.writeNode("AnchorPointX",c,b);this.writeNode("AnchorPointY",d,b)}return b},AnchorPointX:function(a){return this.createElementNSPlus("sld:AnchorPointX",{value:a})},AnchorPointY:function(a){return this.createElementNSPlus("sld:AnchorPointY",{value:a})},Displacement:function(a){var b=this.createElementNSPlus("sld:Displacement");
null!=a.labelXOffset&&this.writeNode("DisplacementX",a.labelXOffset,b);null!=a.labelYOffset&&this.writeNode("DisplacementY",a.labelYOffset,b);return b},DisplacementX:function(a){return this.createElementNSPlus("sld:DisplacementX",{value:a})},DisplacementY:function(a){return this.createElementNSPlus("sld:DisplacementY",{value:a})},Font:function(a){var b=this.createElementNSPlus("sld:Font");a.fontFamily&&this.writeNode("CssParameter",{symbolizer:a,key:"fontFamily"},b);a.fontSize&&this.writeNode("CssParameter",
{symbolizer:a,key:"fontSize"},b);a.fontWeight&&this.writeNode("CssParameter",{symbolizer:a,key:"fontWeight"},b);a.fontStyle&&this.writeNode("CssParameter",{symbolizer:a,key:"fontStyle"},b);return b},Label:function(a){return this.writers.sld._OGCExpression.call(this,"sld:Label",a)},Halo:function(a){var b=this.createElementNSPlus("sld:Halo");a.haloRadius&&this.writeNode("Radius",a.haloRadius,b);(a.haloColor||a.haloOpacity)&&this.writeNode("Fill",{fillColor:a.haloColor,fillOpacity:a.haloOpacity},b);
return b},Radius:function(a){return this.createElementNSPlus("sld:Radius",{value:a})},RasterSymbolizer:function(a){var b=this.createElementNSPlus("sld:RasterSymbolizer");a.geometry&&this.writeNode("Geometry",a.geometry,b);a.opacity&&this.writeNode("Opacity",a.opacity,b);a.colorMap&&this.writeNode("ColorMap",a.colorMap,b);return b},Geometry:function(a){var b=this.createElementNSPlus("sld:Geometry");a.property&&this.writeNode("ogc:PropertyName",a,b);return b},ColorMap:function(a){for(var b=this.createElementNSPlus("sld:ColorMap"),
c=0,d=a.length;c<d;++c)this.writeNode("ColorMapEntry",a[c],b);return b},ColorMapEntry:function(a){var b=this.createElementNSPlus("sld:ColorMapEntry");b.setAttribute("color",a.color);void 0!==a.opacity&&b.setAttribute("opacity",parseFloat(a.opacity));void 0!==a.quantity&&b.setAttribute("quantity",parseFloat(a.quantity));void 0!==a.label&&b.setAttribute("label",a.label);return b},PolygonSymbolizer:function(a){var b=this.createElementNSPlus("sld:PolygonSymbolizer");!1!==a.fill&&this.writeNode("Fill",
a,b);!1!==a.stroke&&this.writeNode("Stroke",a,b);return b},Fill:function(a){var b=this.createElementNSPlus("sld:Fill");a.fillColor&&this.writeNode("CssParameter",{symbolizer:a,key:"fillColor"},b);null!=a.fillOpacity&&this.writeNode("CssParameter",{symbolizer:a,key:"fillOpacity"},b);return b},PointSymbolizer:function(a){var b=this.createElementNSPlus("sld:PointSymbolizer");this.writeNode("Graphic",a,b);return b},Graphic:function(a){var b=this.createElementNSPlus("sld:Graphic");void 0!=a.externalGraphic?
this.writeNode("ExternalGraphic",a,b):this.writeNode("Mark",a,b);void 0!=a.graphicOpacity&&this.writeNode("Opacity",a.graphicOpacity,b);void 0!=a.pointRadius?this.writeNode("Size",2*a.pointRadius,b):void 0!=a.graphicWidth&&this.writeNode("Size",a.graphicWidth,b);void 0!=a.rotation&&this.writeNode("Rotation",a.rotation,b);return b},ExternalGraphic:function(a){var b=this.createElementNSPlus("sld:ExternalGraphic");this.writeNode("OnlineResource",a.externalGraphic,b);a=a.graphicFormat||this.getGraphicFormat(a.externalGraphic);
this.writeNode("Format",a,b);return b},Mark:function(a){var b=this.createElementNSPlus("sld:Mark");a.graphicName&&this.writeNode("WellKnownName",a.graphicName,b);!1!==a.fill&&this.writeNode("Fill",a,b);!1!==a.stroke&&this.writeNode("Stroke",a,b);return b},WellKnownName:function(a){return this.createElementNSPlus("sld:WellKnownName",{value:a})},Opacity:function(a){return this.createElementNSPlus("sld:Opacity",{value:a})},Size:function(a){return this.writers.sld._OGCExpression.call(this,"sld:Size",
a)},Rotation:function(a){return this.createElementNSPlus("sld:Rotation",{value:a})},OnlineResource:function(a){return this.createElementNSPlus("sld:OnlineResource",{attributes:{"xlink:type":"simple","xlink:href":a}})},Format:function(a){return this.createElementNSPlus("sld:Format",{value:a})}}},OpenLayers.Format.Filter.v1_0_0.prototype.writers),CLASS_NAME:"OpenLayers.Format.SLD.v1"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},isBaseLayer:!0,encodeBBOX:!1,noMagic:!1,yx:{},initialize:function(a,b,c,d){var e=[];c=OpenLayers.Util.upperCaseObject(c);1.3<=parseFloat(c.VERSION)&&!c.EXCEPTIONS&&(c.EXCEPTIONS="INIMAGE");e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));
!this.noMagic&&(this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase())&&(null!=d&&d.isBaseLayer||(this.isBaseLayer=!1),"image/jpeg"==this.params.FORMAT&&(this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png"))},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},reverseAxisOrder:function(){var a=this.projection.getCode();return 1.3<=parseFloat(this.params.VERSION)&&
!!(this.yx[a]||OpenLayers.Projection.defaults[a]&&OpenLayers.Projection.defaults[a].yx)},getURL:function(a){a=this.adjustBounds(a);var b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a,b){var c=this.map.getProjectionObject(),
c=this.projection&&this.projection.equals(c)?this.projection.getCode():c.getCode(),c="none"==c?null:c;1.3<=parseFloat(this.params.VERSION)?this.params.CRS=c:this.params.SRS=c;"boolean"==typeof this.params.TRANSPARENT&&(a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE");return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Layer.KaMap=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,DEFAULT_PARAMS:{i:"jpeg",map:""},initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS)},getURL:function(a){a=this.adjustBounds(a);var b=this.map.getResolution(),c=Math.round(1E4*this.map.getScale())/1E4,d=Math.round(a.left/b);a=-Math.round(a.top/b);return this.getFullRequestString({t:a,l:d,s:c})},calculateGridLayout:function(a,
b,c){b=c*this.tileSize.w;c*=this.tileSize.h;return{tilelon:b,tilelat:c,startcol:Math.floor(a.left/b)-this.buffer,startrow:Math.floor(a.top/c)+this.buffer}},getTileBoundsForGridIndex:function(a,b){this.getTileOrigin();var c=this.gridLayout,d=c.tilelon,e=c.tilelat,f=(c.startcol+b)*d,c=(c.startrow-a)*e;return new OpenLayers.Bounds(f,c,f+d,c+e)},clone:function(a){null==a&&(a=new OpenLayers.Layer.KaMap(this.name,this.url,this.params,this.getOptions()));a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
[a]);null!=this.tileSize&&(a.tileSize=this.tileSize.clone());a.grid=[];return a},getTileBounds:function(a){var b=this.getResolution(),c=b*this.tileSize.w,b=b*this.tileSize.h,d=this.getLonLatFromViewPortPx(a);a=c*Math.floor(d.lon/c);d=b*Math.floor(d.lat/b);return new OpenLayers.Bounds(a,d,a+c,d+b)},CLASS_NAME:"OpenLayers.Layer.KaMap"});OpenLayers.Format.WMC.v1_1_0=OpenLayers.Class(OpenLayers.Format.WMC.v1,{VERSION:"1.1.0",schemaLocation:"http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd",initialize:function(a){OpenLayers.Format.WMC.v1.prototype.initialize.apply(this,[a])},read_sld_MinScaleDenominator:function(a,b){var c=parseFloat(this.getChildValue(b));0<c&&(a.maxScale=c)},read_sld_MaxScaleDenominator:function(a,b){a.minScale=parseFloat(this.getChildValue(b))},read_wmc_SRS:function(a,b){"srs"in
a||(a.srs={});a.srs[this.getChildValue(b)]=!0},write_wmc_Layer:function(a){var b=OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this,[a]);if(a.maxScale){var c=this.createElementNS(this.namespaces.sld,"sld:MinScaleDenominator");c.appendChild(this.createTextNode(a.maxScale.toPrecision(16)));b.appendChild(c)}a.minScale&&(c=this.createElementNS(this.namespaces.sld,"sld:MaxScaleDenominator"),c.appendChild(this.createTextNode(a.minScale.toPrecision(16))),b.appendChild(c));if(a.srs)for(var d in a.srs)b.appendChild(this.createElementDefaultNS("SRS",
d));b.appendChild(this.write_wmc_FormatList(a));b.appendChild(this.write_wmc_StyleList(a));a.dimensions&&b.appendChild(this.write_wmc_DimensionList(a));b.appendChild(this.write_wmc_LayerExtension(a));return b},CLASS_NAME:"OpenLayers.Format.WMC.v1_1_0"});OpenLayers.Format.XLS=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.0",stringifyOutput:!0,CLASS_NAME:"OpenLayers.Format.XLS"});OpenLayers.Format.XLS.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xls:"http://www.opengis.net/xls",gml:"http://www.opengis.net/gml",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},xy:!0,defaultPrefix:"xls",schemaLocation:null,read:function(a,b){OpenLayers.Util.applyDefaults(b,this.options);var c={};this.readChildNodes(a,c);return c},readers:{xls:{XLS:function(a,b){b.version=a.getAttribute("version");
this.readChildNodes(a,b)},Response:function(a,b){this.readChildNodes(a,b)},GeocodeResponse:function(a,b){b.responseLists=[];this.readChildNodes(a,b)},GeocodeResponseList:function(a,b){var c={features:[],numberOfGeocodedAddresses:parseInt(a.getAttribute("numberOfGeocodedAddresses"))};b.responseLists.push(c);this.readChildNodes(a,c)},GeocodedAddress:function(a,b){var c=new OpenLayers.Feature.Vector;b.features.push(c);this.readChildNodes(a,c);c.geometry=c.components[0]},GeocodeMatchCode:function(a,b){b.attributes.matchCode=
{accuracy:parseFloat(a.getAttribute("accuracy")),matchType:a.getAttribute("matchType")}},Address:function(a,b){var c={countryCode:a.getAttribute("countryCode"),addressee:a.getAttribute("addressee"),street:[],place:[]};b.attributes.address=c;this.readChildNodes(a,c)},freeFormAddress:function(a,b){b.freeFormAddress=this.getChildValue(a)},StreetAddress:function(a,b){this.readChildNodes(a,b)},Building:function(a,b){b.building={number:a.getAttribute("number"),subdivision:a.getAttribute("subdivision"),
buildingName:a.getAttribute("buildingName")}},Street:function(a,b){b.street.push(this.getChildValue(a))},Place:function(a,b){b.place[a.getAttribute("type")]=this.getChildValue(a)},PostalCode:function(a,b){b.postalCode=this.getChildValue(a)}},gml:OpenLayers.Format.GML.v3.prototype.readers.gml},write:function(a){return this.writers.xls.XLS.apply(this,[a])},writers:{xls:{XLS:function(a){var b=this.createElementNSPlus("xls:XLS",{attributes:{version:this.VERSION,"xsi:schemaLocation":this.schemaLocation}});
this.writeNode("RequestHeader",a.header,b);this.writeNode("Request",a,b);return b},RequestHeader:function(a){return this.createElementNSPlus("xls:RequestHeader")},Request:function(a){var b=this.createElementNSPlus("xls:Request",{attributes:{methodName:"GeocodeRequest",requestID:a.requestID||"",version:this.VERSION}});this.writeNode("GeocodeRequest",a.addresses,b);return b},GeocodeRequest:function(a){for(var b=this.createElementNSPlus("xls:GeocodeRequest"),c=0,d=a.length;c<d;c++)this.writeNode("Address",
a[c],b);return b},Address:function(a){var b=this.createElementNSPlus("xls:Address",{attributes:{countryCode:a.countryCode}});a.freeFormAddress?this.writeNode("freeFormAddress",a.freeFormAddress,b):(a.street&&this.writeNode("StreetAddress",a,b),a.municipality&&this.writeNode("Municipality",a.municipality,b),a.countrySubdivision&&this.writeNode("CountrySubdivision",a.countrySubdivision,b),a.postalCode&&this.writeNode("PostalCode",a.postalCode,b));return b},freeFormAddress:function(a){return this.createElementNSPlus("freeFormAddress",
{value:a})},StreetAddress:function(a){var b=this.createElementNSPlus("xls:StreetAddress");a.building&&this.writeNode(b,"Building",a.building);a=a.street;OpenLayers.Util.isArray(a)||(a=[a]);for(var c=0,d=a.length;c<d;c++)this.writeNode("Street",a[c],b);return b},Building:function(a){return this.createElementNSPlus("xls:Building",{attributes:{number:a.number,subdivision:a.subdivision,buildingName:a.buildingName}})},Street:function(a){return this.createElementNSPlus("xls:Street",{value:a})},Municipality:function(a){return this.createElementNSPlus("xls:Place",
{attributes:{type:"Municipality"},value:a})},CountrySubdivision:function(a){return this.createElementNSPlus("xls:Place",{attributes:{type:"CountrySubdivision"},value:a})},PostalCode:function(a){return this.createElementNSPlus("xls:PostalCode",{value:a})}}},CLASS_NAME:"OpenLayers.Format.XLS.v1"});OpenLayers.Format.XLS.v1_1_0=OpenLayers.Class(OpenLayers.Format.XLS.v1,{VERSION:"1.1",schemaLocation:"http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd",CLASS_NAME:"OpenLayers.Format.XLS.v1_1_0"});OpenLayers.Format.XLS.v1_1=OpenLayers.Format.XLS.v1_1_0;OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15E3,translationParameters:null,symbolMetrics:null,initialize:function(a){this.supported()&&(OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments),this.translationParameters={x:0,y:0},this.symbolMetrics={})},supported:function(){return document.implementation&&(document.implementation.hasFeature("org.w3c.svg","1.0")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#SVG",
"1.1")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1"))},inValidRange:function(a,b,c){a+=c?0:this.translationParameters.x;b+=c?0:this.translationParameters.y;return a>=-this.MAX_PIXEL&&a<=this.MAX_PIXEL&&b>=-this.MAX_PIXEL&&b<=this.MAX_PIXEL},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=-a.left/d,d=a.top/d;if(b)return this.left=e,this.top=d,this.rendererRoot.setAttributeNS(null,
"viewBox","0 0 "+this.size.w+" "+this.size.h),this.translate(this.xOffset,0),!0;(e=this.translate(e-this.left+this.xOffset,d-this.top))||this.setExtent(a,!0);return c&&e},translate:function(a,b){if(this.inValidRange(a,b,!0)){var c="";if(a||b)c="translate("+a+","+b+")";this.root.setAttributeNS(null,"transform",c);this.translationParameters={x:a,y:b};return!0}return!1},setSize:function(a){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null,"width",this.size.w);
this.rendererRoot.setAttributeNS(null,"height",this.size.h)},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"image":this.isComplexSymbol(b.graphicName)?"svg":"circle";break;case "OpenLayers.Geometry.Rectangle":c="rect";break;case "OpenLayers.Geometry.LineString":c="polyline";break;case "OpenLayers.Geometry.LinearRing":c="polygon";break;case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c="path"}return c},setStyle:function(a,
b,c){b=b||a._style;c=c||a._options;var d=b.title||b.graphicTitle;if(d){a.setAttributeNS(null,"title",d);var e=a.getElementsByTagName("title");0<e.length?e[0].firstChild.textContent=d:(e=this.nodeFactory(null,"title"),e.textContent=d,a.appendChild(e))}var e=parseFloat(a.getAttributeNS(null,"r")),d=1,f;if("OpenLayers.Geometry.Point"==a._geometryClass&&e){a.style.visibility="";if(!1===b.graphic)a.style.visibility="hidden";else if(b.externalGraphic){f=this.getPosition(a);b.graphicWidth&&b.graphicHeight&&
a.setAttributeNS(null,"preserveAspectRatio","none");var e=b.graphicWidth||b.graphicHeight,g=b.graphicHeight||b.graphicWidth,e=e?e:2*b.pointRadius,g=g?g:2*b.pointRadius,h=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*g),k=b.graphicOpacity||b.fillOpacity;a.setAttributeNS(null,"x",(f.x+(void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*e))).toFixed());a.setAttributeNS(null,"y",(f.y+h).toFixed());a.setAttributeNS(null,"width",e);a.setAttributeNS(null,"height",g);a.setAttributeNS(this.xlinkns,"xlink:href",
b.externalGraphic);a.setAttributeNS(null,"style","opacity: "+k);a.onclick=OpenLayers.Event.preventDefault}else if(this.isComplexSymbol(b.graphicName)){var e=3*b.pointRadius,g=2*e,l=this.importSymbol(b.graphicName);f=this.getPosition(a);d=3*this.symbolMetrics[l.id][0]/g;h=a.parentNode;k=a.nextSibling;h&&h.removeChild(a);a.firstChild&&a.removeChild(a.firstChild);a.appendChild(l.firstChild.cloneNode(!0));a.setAttributeNS(null,"viewBox",l.getAttributeNS(null,"viewBox"));a.setAttributeNS(null,"width",
g);a.setAttributeNS(null,"height",g);a.setAttributeNS(null,"x",f.x-e);a.setAttributeNS(null,"y",f.y-e);k?h.insertBefore(a,k):h&&h.appendChild(a)}else a.setAttributeNS(null,"r",b.pointRadius);e=b.rotation;void 0===e&&void 0===a._rotation||!f||(a._rotation=e,e|=0,"svg"!==a.nodeName?a.setAttributeNS(null,"transform","rotate("+e+" "+f.x+" "+f.y+")"):(f=this.symbolMetrics[l.id],a.firstChild.setAttributeNS(null,"transform","rotate("+e+" "+f[1]+" "+f[2]+")")))}c.isFilled?(a.setAttributeNS(null,"fill",b.fillColor),
a.setAttributeNS(null,"fill-opacity",b.fillOpacity)):a.setAttributeNS(null,"fill","none");c.isStroked?(a.setAttributeNS(null,"stroke",b.strokeColor),a.setAttributeNS(null,"stroke-opacity",b.strokeOpacity),a.setAttributeNS(null,"stroke-width",b.strokeWidth*d),a.setAttributeNS(null,"stroke-linecap",b.strokeLinecap||"round"),a.setAttributeNS(null,"stroke-linejoin","round"),b.strokeDashstyle&&a.setAttributeNS(null,"stroke-dasharray",this.dashStyle(b,d))):a.setAttributeNS(null,"stroke","none");b.pointerEvents&&
a.setAttributeNS(null,"pointer-events",b.pointerEvents);null!=b.cursor&&a.setAttributeNS(null,"cursor",b.cursor);return a},dashStyle:function(a,b){var c=a.strokeWidth*b,d=a.strokeDashstyle;switch(d){case "solid":return"none";case "dot":return[1,4*c].join();case "dash":return[4*c,4*c].join();case "dashdot":return[4*c,4*c,1,4*c].join();case "longdash":return[8*c,4*c].join();case "longdashdot":return[8*c,4*c,1,4*c].join();default:return OpenLayers.String.trim(d).replace(/\s+/g,",")}},createNode:function(a,
b){var c=document.createElementNS(this.xmlns,a);b&&c.setAttributeNS(null,"id",b);return c},nodeTypeCompare:function(a,b){return b==a.nodeName},createRenderRoot:function(){var a=this.nodeFactory(this.container.id+"_svgRoot","svg");a.style.display="block";return a},createRoot:function(a){return this.nodeFactory(this.container.id+a,"g")},createDefs:function(){var a=this.nodeFactory(this.container.id+"_defs","defs");this.rendererRoot.appendChild(a);return a},drawPoint:function(a,b){return this.drawCircle(a,
b,1)},drawCircle:function(a,b,c){var d=this.getResolution(),e=(b.x-this.featureDx)/d+this.left;b=this.top-b.y/d;return this.inValidRange(e,b)?(a.setAttributeNS(null,"cx",e),a.setAttributeNS(null,"cy",b),a.setAttributeNS(null,"r",c),a):!1},drawLineString:function(a,b){var c=this.getComponentsString(b.components);return c.path?(a.setAttributeNS(null,"points",c.path),c.complete?a:null):!1},drawLinearRing:function(a,b){var c=this.getComponentsString(b.components);return c.path?(a.setAttributeNS(null,
"points",c.path),c.complete?a:null):!1},drawPolygon:function(a,b){for(var c="",d=!0,e=!0,f,g,h=0,k=b.components.length;h<k;h++)c+=" M",f=this.getComponentsString(b.components[h].components," "),(g=f.path)?(c+=" "+g,e=f.complete&&e):d=!1;return d?(a.setAttributeNS(null,"d",c+" z"),a.setAttributeNS(null,"fill-rule","evenodd"),e?a:null):!1},drawRectangle:function(a,b){var c=this.getResolution(),d=(b.x-this.featureDx)/c+this.left,e=this.top-b.y/c;return this.inValidRange(d,e)?(a.setAttributeNS(null,"x",
d),a.setAttributeNS(null,"y",e),a.setAttributeNS(null,"width",b.width/c),a.setAttributeNS(null,"height",b.height/c),a):!1},drawText:function(a,b,c){var d=!!b.labelOutlineWidth;if(d){var e=OpenLayers.Util.extend({},b);e.fontColor=e.labelOutlineColor;e.fontStrokeColor=e.labelOutlineColor;e.fontStrokeWidth=b.labelOutlineWidth;b.labelOutlineOpacity&&(e.fontOpacity=b.labelOutlineOpacity);delete e.labelOutlineWidth;this.drawText(a,e,c)}var f=this.getResolution(),e=(c.x-this.featureDx)/f+this.left,g=c.y/
f-this.top,d=d?this.LABEL_OUTLINE_SUFFIX:this.LABEL_ID_SUFFIX,f=this.nodeFactory(a+d,"text");f.setAttributeNS(null,"x",e);f.setAttributeNS(null,"y",-g);b.fontColor&&f.setAttributeNS(null,"fill",b.fontColor);b.fontStrokeColor&&f.setAttributeNS(null,"stroke",b.fontStrokeColor);b.fontStrokeWidth&&f.setAttributeNS(null,"stroke-width",b.fontStrokeWidth);b.fontOpacity&&f.setAttributeNS(null,"opacity",b.fontOpacity);b.fontFamily&&f.setAttributeNS(null,"font-family",b.fontFamily);b.fontSize&&f.setAttributeNS(null,
"font-size",b.fontSize);b.fontWeight&&f.setAttributeNS(null,"font-weight",b.fontWeight);b.fontStyle&&f.setAttributeNS(null,"font-style",b.fontStyle);!0===b.labelSelect?(f.setAttributeNS(null,"pointer-events","visible"),f._featureId=a):f.setAttributeNS(null,"pointer-events","none");g=b.labelAlign||OpenLayers.Renderer.defaultSymbolizer.labelAlign;f.setAttributeNS(null,"text-anchor",OpenLayers.Renderer.SVG.LABEL_ALIGN[g[0]]||"middle");!0===OpenLayers.IS_GECKO&&f.setAttributeNS(null,"dominant-baseline",
OpenLayers.Renderer.SVG.LABEL_ALIGN[g[1]]||"central");for(var h=b.label.split("\n"),k=h.length;f.childNodes.length>k;)f.removeChild(f.lastChild);for(var l=0;l<k;l++){var m=this.nodeFactory(a+d+"_tspan_"+l,"tspan");!0===b.labelSelect&&(m._featureId=a,m._geometry=c,m._geometryClass=c.CLASS_NAME);!1===OpenLayers.IS_GECKO&&m.setAttributeNS(null,"baseline-shift",OpenLayers.Renderer.SVG.LABEL_VSHIFT[g[1]]||"-35%");m.setAttribute("x",e);if(0==l){var n=OpenLayers.Renderer.SVG.LABEL_VFACTOR[g[1]];null==n&&
(n=-0.5);m.setAttribute("dy",n*(k-1)+"em")}else m.setAttribute("dy","1em");m.textContent=""===h[l]?" ":h[l];m.parentNode||f.appendChild(m)}f.parentNode||this.textRoot.appendChild(f)},getComponentsString:function(a,b){for(var c=[],d=!0,e=a.length,f=[],g,h=0;h<e;h++)g=a[h],c.push(g),(g=this.getShortString(g))?f.push(g):(0<h&&this.getShortString(a[h-1])&&f.push(this.clipLine(a[h],a[h-1])),h<e-1&&this.getShortString(a[h+1])&&f.push(this.clipLine(a[h],a[h+1])),d=!1);return{path:f.join(b||","),complete:d}},
clipLine:function(a,b){if(b.equals(a))return"";var c=this.getResolution(),d=this.MAX_PIXEL-this.translationParameters.x,e=this.MAX_PIXEL-this.translationParameters.y,f=(b.x-this.featureDx)/c+this.left,g=this.top-b.y/c,h=(a.x-this.featureDx)/c+this.left,c=this.top-a.y/c,k;if(h<-d||h>d)k=(c-g)/(h-f),h=0>h?-d:d,c=g+(h-f)*k;if(c<-e||c>e)k=(h-f)/(c-g),c=0>c?-e:e,h=f+(c-g)*k;return h+","+c},getShortString:function(a){var b=this.getResolution(),c=(a.x-this.featureDx)/b+this.left;a=this.top-a.y/b;return this.inValidRange(c,
a)?c+","+a:!1},getPosition:function(a){return{x:parseFloat(a.getAttributeNS(null,"cx")),y:parseFloat(a.getAttributeNS(null,"cy"))}},importSymbol:function(a){this.defs||(this.defs=this.createDefs());var b=this.container.id+"-"+a,c=document.getElementById(b);if(null!=c)return c;var d=OpenLayers.Renderer.symbol[a];if(!d)throw Error(a+" is not a valid symbol name");a=this.nodeFactory(b,"symbol");var e=this.nodeFactory(null,"polygon");a.appendChild(e);for(var c=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,
0,0),f=[],g,h,k=0;k<d.length;k+=2)g=d[k],h=d[k+1],c.left=Math.min(c.left,g),c.bottom=Math.min(c.bottom,h),c.right=Math.max(c.right,g),c.top=Math.max(c.top,h),f.push(g,",",h);e.setAttributeNS(null,"points",f.join(" "));d=c.getWidth();e=c.getHeight();a.setAttributeNS(null,"viewBox",[c.left-d,c.bottom-e,3*d,3*e].join(" "));this.symbolMetrics[b]=[Math.max(d,e),c.getCenterLonLat().lon,c.getCenterLonLat().lat];this.defs.appendChild(a);return a},getFeatureIdFromEvent:function(a){var b=OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this,
arguments);b||(b=a.target,b=b.parentNode&&b!=this.rendererRoot?b.parentNode._featureId:void 0);return b},CLASS_NAME:"OpenLayers.Renderer.SVG"});OpenLayers.Renderer.SVG.LABEL_ALIGN={l:"start",r:"end",b:"bottom",t:"hanging"};OpenLayers.Renderer.SVG.LABEL_VSHIFT={t:"-70%",b:"0"};OpenLayers.Renderer.SVG.LABEL_VFACTOR={t:0,b:-1};OpenLayers.Renderer.SVG.preventDefault=function(a){OpenLayers.Event.preventDefault(a)};OpenLayers.Format.SLD.v1_0_0=OpenLayers.Class(OpenLayers.Format.SLD.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd",CLASS_NAME:"OpenLayers.Format.SLD.v1_0_0"});OpenLayers.Format.OWSContext=OpenLayers.Class(OpenLayers.Format.Context,{defaultVersion:"0.3.1",getVersion:function(a,b){var c=OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply(this,arguments);"0.3.0"===c&&(c=this.defaultVersion);return c},toContext:function(a){var b={};"OpenLayers.Map"==a.CLASS_NAME&&(b.bounds=a.getExtent(),b.maxExtent=a.maxExtent,b.projection=a.projection,b.size=a.getSize(),b.layers=a.layers);return b},CLASS_NAME:"OpenLayers.Format.OWSContext"});OpenLayers.Format.OWSContext.v0_3_1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{owc:"http://www.opengis.net/ows-context",gml:"http://www.opengis.net/gml",kml:"http://www.opengis.net/kml/2.2",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},VERSION:"0.3.1",schemaLocation:"http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd",
defaultPrefix:"owc",extractAttributes:!0,xy:!0,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},featureNS:"http://mapserver.gis.umn.edu/mapserver",featureType:"vector",geometryName:"geometry",nestingLayerLookup:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this)},setNestingPath:function(a){if(a.layersContext)for(var b=0,c=a.layersContext.length;b<c;b++){var d=
a.layersContext[b],e=[],f=a.title||"";a.metadata&&a.metadata.nestingPath&&(e=a.metadata.nestingPath.slice());""!=f&&e.push(f);d.metadata.nestingPath=e;d.layersContext&&this.setNestingPath(d)}},decomposeNestingPath:function(a){var b=[];if(OpenLayers.Util.isArray(a)){for(a=a.slice();0<a.length;)b.push(a.slice()),a.pop();b.reverse()}return b},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,
b);this.setNestingPath({layersContext:b.layersContext});a=[];this.processLayer(a,b);delete b.layersContext;b.layersContext=a;return b},processLayer:function(a,b){if(b.layersContext)for(var c=0,d=b.layersContext.length;c<d;c++){var e=b.layersContext[c];a.push(e);e.layersContext&&this.processLayer(a,e)}},write:function(a,b){this.nestingLayerLookup={};b=b||{};OpenLayers.Util.applyDefaults(b,a);var c=this.writeNode("OWSContext",b);this.nestingLayerLookup=null;this.setAttributeNS(c,this.namespaces.xsi,
"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[c])},readers:{kml:{Document:function(a,b){b.features=(new OpenLayers.Format.KML({kmlns:this.namespaces.kml,extractStyles:!0})).read(a)}},owc:{OWSContext:function(a,b){this.readChildNodes(a,b)},General:function(a,b){this.readChildNodes(a,b)},ResourceList:function(a,b){this.readChildNodes(a,b)},Layer:function(a,b){var c={metadata:{},visibility:"1"!=a.getAttribute("hidden"),queryable:"1"==a.getAttribute("queryable"),
opacity:null!=a.getAttribute("opacity")?parseFloat(a.getAttribute("opacity")):null,name:a.getAttribute("name"),categoryLayer:null==a.getAttribute("name"),formats:[],styles:[]};b.layersContext||(b.layersContext=[]);b.layersContext.push(c);this.readChildNodes(a,c)},InlineGeometry:function(a,b){b.features=[];var c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMember"),d;1<=c.length&&(d=c[0]);d&&d.firstChild&&(c=d.firstChild.nextSibling?d.firstChild.nextSibling:d.firstChild,this.setNamespace("feature",
c.namespaceURI),this.featureType=c.localName||c.nodeName.split(":").pop(),this.readChildNodes(a,b))},Server:function(a,b){if(!b.service&&!b.version||b.service!=OpenLayers.Format.Context.serviceTypes.WMS)b.service=a.getAttribute("service"),b.version=a.getAttribute("version"),this.readChildNodes(a,b)},Name:function(a,b){b.name=this.getChildValue(a);this.readChildNodes(a,b)},Title:function(a,b){b.title=this.getChildValue(a);this.readChildNodes(a,b)},StyleList:function(a,b){this.readChildNodes(a,b.styles)},
Style:function(a,b){var c={};b.push(c);this.readChildNodes(a,c)},LegendURL:function(a,b){var c={};b.legend=c;this.readChildNodes(a,c)},OnlineResource:function(a,b){b.url=this.getAttributeNS(a,this.namespaces.xlink,"href");this.readChildNodes(a,b)}},ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows,gml:OpenLayers.Format.GML.v2.prototype.readers.gml,sld:OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld,feature:OpenLayers.Format.GML.v2.prototype.readers.feature},writers:{owc:{OWSContext:function(a){var b=
this.createElementNSPlus("OWSContext",{attributes:{version:this.VERSION,id:a.id||OpenLayers.Util.createUniqueID("OpenLayers_OWSContext_")}});this.writeNode("General",a,b);this.writeNode("ResourceList",a,b);return b},General:function(a){var b=this.createElementNSPlus("General");this.writeNode("ows:BoundingBox",a,b);this.writeNode("ows:Title",a.title||"OpenLayers OWSContext",b);return b},ResourceList:function(a){for(var b=this.createElementNSPlus("ResourceList"),c=0,d=a.layers.length;c<d;c++){var e=
a.layers[c],f=this.decomposeNestingPath(e.metadata.nestingPath);this.writeNode("_Layer",{layer:e,subPaths:f},b)}return b},Server:function(a){var b=this.createElementNSPlus("Server",{attributes:{version:a.version,service:a.service}});this.writeNode("OnlineResource",a,b);return b},OnlineResource:function(a){return this.createElementNSPlus("OnlineResource",{attributes:{"xlink:href":a.url}})},InlineGeometry:function(a){var b=this.createElementNSPlus("InlineGeometry"),c=a.getDataExtent();null!==c&&this.writeNode("gml:boundedBy",
c,b);for(var c=0,d=a.features.length;c<d;c++)this.writeNode("gml:featureMember",a.features[c],b);return b},StyleList:function(a){for(var b=this.createElementNSPlus("StyleList"),c=0,d=a.length;c<d;c++)this.writeNode("Style",a[c],b);return b},Style:function(a){var b=this.createElementNSPlus("Style");this.writeNode("Name",a,b);this.writeNode("Title",a,b);a.legend&&this.writeNode("LegendURL",a,b);return b},Name:function(a){return this.createElementNSPlus("Name",{value:a.name})},Title:function(a){return this.createElementNSPlus("Title",
{value:a.title})},LegendURL:function(a){var b=this.createElementNSPlus("LegendURL");this.writeNode("OnlineResource",a.legend,b);return b},_WMS:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:a.params.LAYERS,queryable:a.queryable?"1":"0",hidden:a.visibility?"0":"1",opacity:a.hasOwnProperty("opacity")?a.opacity:null}});this.writeNode("ows:Title",a.name,b);this.writeNode("ows:OutputFormat",a.params.FORMAT,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.WMS,
version:a.params.VERSION,url:a.url},b);a.metadata.styles&&0<a.metadata.styles.length&&this.writeNode("StyleList",a.metadata.styles,b);return b},_Layer:function(a){var b,c,d;b=a.layer;c=a.subPaths;d=null;0<c.length?(b=c[0].join("/"),c=b.lastIndexOf("/"),d=this.nestingLayerLookup[b],c=0<c?b.substring(c+1,b.length):b,d||(d=this.createElementNSPlus("Layer"),this.writeNode("ows:Title",c,d),this.nestingLayerLookup[b]=d),a.subPaths.shift(),this.writeNode("_Layer",a,d)):(b instanceof OpenLayers.Layer.WMS?
d=this.writeNode("_WMS",b):b instanceof OpenLayers.Layer.Vector&&(b.protocol instanceof OpenLayers.Protocol.WFS.v1?d=this.writeNode("_WFS",b):b.protocol instanceof OpenLayers.Protocol.HTTP?b.protocol.format instanceof OpenLayers.Format.GML?(b.protocol.format.version="2.1.2",d=this.writeNode("_GML",b)):b.protocol.format instanceof OpenLayers.Format.KML&&(b.protocol.format.version="2.2",d=this.writeNode("_KML",b)):(this.setNamespace("feature",this.featureNS),d=this.writeNode("_InlineGeometry",b))),
b.options.maxScale&&this.writeNode("sld:MinScaleDenominator",b.options.maxScale,d),b.options.minScale&&this.writeNode("sld:MaxScaleDenominator",b.options.minScale,d),this.nestingLayerLookup[b.name]=d);return d},_WFS:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:a.protocol.featurePrefix+":"+a.protocol.featureType,hidden:a.visibility?"0":"1"}});this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.WFS,version:a.protocol.version,
url:a.protocol.url},b);return b},_InlineGeometry:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:this.featureType,hidden:a.visibility?"0":"1"}});this.writeNode("ows:Title",a.name,b);this.writeNode("InlineGeometry",a,b);return b},_GML:function(a){var b=this.createElementNSPlus("Layer");this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.GML,url:a.protocol.url,version:a.protocol.format.version},b);return b},_KML:function(a){var b=
this.createElementNSPlus("Layer");this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.KML,version:a.protocol.format.version,url:a.protocol.url},b);return b}},gml:OpenLayers.Util.applyDefaults({boundedBy:function(a){var b=this.createElementNSPlus("gml:boundedBy");this.writeNode("gml:Box",a,b);return b}},OpenLayers.Format.GML.v2.prototype.writers.gml),ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows,sld:OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld,
feature:OpenLayers.Format.GML.v2.prototype.writers.feature},CLASS_NAME:"OpenLayers.Format.OWSContext.v0_3_1"});OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,contentSize:null,size:null,contentHTML:null,backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:!1,minSize:null,maxSize:null,displayClass:"olPopup",contentDisplayClass:"olPopupContent",padding:0,disableFirefoxOverflowHack:!1,fixPadding:function(){"number"==typeof this.padding&&(this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding))},panMapIfOutOfView:!1,
keepInMap:!1,closeOnMove:!1,map:null,initialize:function(a,b,c,d,e,f){null==a&&(a=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_"));this.id=a;this.lonlat=b;this.contentSize=null!=c?c:new OpenLayers.Size(OpenLayers.Popup.WIDTH,OpenLayers.Popup.HEIGHT);null!=d&&(this.contentHTML=d);this.backgroundColor=OpenLayers.Popup.COLOR;this.opacity=OpenLayers.Popup.OPACITY;this.border=OpenLayers.Popup.BORDER;this.div=OpenLayers.Util.createDiv(this.id,null,null,null,null,null,"hidden");this.div.className=this.displayClass;
this.groupDiv=OpenLayers.Util.createDiv(this.id+"_GroupDiv",null,null,null,"relative",null,"hidden");a=this.div.id+"_contentDiv";this.contentDiv=OpenLayers.Util.createDiv(a,null,this.contentSize.clone(),null,"relative");this.contentDiv.className=this.contentDisplayClass;this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);e&&this.addCloseBox(f);this.registerEvents()},destroy:function(){this.border=this.opacity=this.backgroundColor=this.contentHTML=this.size=this.lonlat=this.id=
null;this.closeOnMove&&this.map&&this.map.events.unregister("movestart",this,this.hide);this.events.destroy();this.events=null;this.closeDiv&&(OpenLayers.Event.stopObservingElement(this.closeDiv),this.groupDiv.removeChild(this.closeDiv));this.closeDiv=null;this.div.removeChild(this.groupDiv);this.groupDiv=null;null!=this.map&&this.map.removePopup(this);this.panMapIfOutOfView=this.padding=this.maxSize=this.minSize=this.autoSize=this.div=this.map=null},draw:function(a){null==a&&null!=this.lonlat&&null!=
this.map&&(a=this.map.getLayerPxFromLonLat(this.lonlat));this.closeOnMove&&this.map.events.register("movestart",this,this.hide);this.disableFirefoxOverflowHack||"firefox"!=OpenLayers.BROWSER_NAME||(this.map.events.register("movestart",this,function(){var a=document.defaultView.getComputedStyle(this.contentDiv,null).getPropertyValue("overflow");"hidden"!=a&&(this.contentDiv._oldOverflow=a,this.contentDiv.style.overflow="hidden")}),this.map.events.register("moveend",this,function(){var a=this.contentDiv._oldOverflow;
a&&(this.contentDiv.style.overflow=a,this.contentDiv._oldOverflow=null)}));this.moveTo(a);this.autoSize||this.size||this.setSize(this.contentSize);this.setBackgroundColor();this.setOpacity();this.setBorder();this.setContentHTML();this.panMapIfOutOfView&&this.panIntoView();return this.div},updatePosition:function(){if(this.lonlat&&this.map){var a=this.map.getLayerPxFromLonLat(this.lonlat);a&&this.moveTo(a)}},moveTo:function(a){null!=a&&null!=this.div&&(this.div.style.left=a.x+"px",this.div.style.top=
a.y+"px")},visible:function(){return OpenLayers.Element.visible(this.div)},toggle:function(){this.visible()?this.hide():this.show()},show:function(){this.div.style.display="";this.panMapIfOutOfView&&this.panIntoView()},hide:function(){this.div.style.display="none"},setSize:function(a){this.size=a.clone();var b=this.getContentDivPadding(),c=b.left+b.right,d=b.top+b.bottom;this.fixPadding();c+=this.padding.left+this.padding.right;d+=this.padding.top+this.padding.bottom;if(this.closeDiv)var e=parseInt(this.closeDiv.style.width),
c=c+(e+b.right);this.size.w+=c;this.size.h+=d;"msie"==OpenLayers.BROWSER_NAME&&(this.contentSize.w+=b.left+b.right,this.contentSize.h+=b.bottom+b.top);null!=this.div&&(this.div.style.width=this.size.w+"px",this.div.style.height=this.size.h+"px");null!=this.contentDiv&&(this.contentDiv.style.width=a.w+"px",this.contentDiv.style.height=a.h+"px")},updateSize:function(){var a="<div class='"+this.contentDisplayClass+"'>"+this.contentDiv.innerHTML+"</div>",b=this.map?this.map.div:document.body,c=OpenLayers.Util.getRenderedDimensions(a,
null,{displayClass:this.displayClass,containerElement:b}),d=this.getSafeContentSize(c),e=null;d.equals(c)?e=c:(c={w:d.w<c.w?d.w:null,h:d.h<c.h?d.h:null},c.w&&c.h?e=d:(a=OpenLayers.Util.getRenderedDimensions(a,c,{displayClass:this.contentDisplayClass,containerElement:b}),"hidden"!=OpenLayers.Element.getStyle(this.contentDiv,"overflow")&&a.equals(d)&&(d=OpenLayers.Util.getScrollbarWidth(),c.w?a.h+=d:a.w+=d),e=this.getSafeContentSize(a)));this.setSize(e)},setBackgroundColor:function(a){void 0!=a&&(this.backgroundColor=
a);null!=this.div&&(this.div.style.backgroundColor=this.backgroundColor)},setOpacity:function(a){void 0!=a&&(this.opacity=a);null!=this.div&&(this.div.style.opacity=this.opacity,this.div.style.filter="alpha(opacity="+100*this.opacity+")")},setBorder:function(a){void 0!=a&&(this.border=a);null!=this.div&&(this.div.style.border=this.border)},setContentHTML:function(a){null!=a&&(this.contentHTML=a);null!=this.contentDiv&&(null!=this.contentHTML&&this.contentHTML!=this.contentDiv.innerHTML)&&(this.contentDiv.innerHTML=
this.contentHTML,this.autoSize&&(this.registerImageListeners(),this.updateSize()))},registerImageListeners:function(){for(var a=function(){null!==this.popup.id&&(this.popup.updateSize(),this.popup.visible()&&this.popup.panMapIfOutOfView&&this.popup.panIntoView(),OpenLayers.Event.stopObserving(this.img,"load",this.img._onImgLoad))},b=this.contentDiv.getElementsByTagName("img"),c=0,d=b.length;c<d;c++){var e=b[c];if(0==e.width||0==e.height)e._onImgLoad=OpenLayers.Function.bind(a,{popup:this,img:e}),
OpenLayers.Event.observe(e,"load",e._onImgLoad)}},getSafeContentSize:function(a){a=a.clone();var b=this.getContentDivPadding(),c=b.left+b.right,d=b.top+b.bottom;this.fixPadding();c+=this.padding.left+this.padding.right;d+=this.padding.top+this.padding.bottom;if(this.closeDiv)var e=parseInt(this.closeDiv.style.width),c=c+(e+b.right);this.minSize&&(a.w=Math.max(a.w,this.minSize.w-c),a.h=Math.max(a.h,this.minSize.h-d));this.maxSize&&(a.w=Math.min(a.w,this.maxSize.w-c),a.h=Math.min(a.h,this.maxSize.h-
d));if(this.map&&this.map.size){e=b=0;if(this.keepInMap&&!this.panMapIfOutOfView)switch(e=this.map.getPixelFromLonLat(this.lonlat),this.relativePosition){case "tr":b=e.x;e=this.map.size.h-e.y;break;case "tl":b=this.map.size.w-e.x;e=this.map.size.h-e.y;break;case "bl":b=this.map.size.w-e.x;e=e.y;break;case "br":b=e.x;e=e.y;break;default:b=e.x,e=this.map.size.h-e.y}d=this.map.size.h-this.map.paddingForPopups.top-this.map.paddingForPopups.bottom-d-e;a.w=Math.min(a.w,this.map.size.w-this.map.paddingForPopups.left-
this.map.paddingForPopups.right-c-b);a.h=Math.min(a.h,d)}return a},getContentDivPadding:function(){var a=this._contentDivPadding;a||(null==this.div.parentNode&&(this.div.style.display="none",document.body.appendChild(this.div)),this._contentDivPadding=a=new OpenLayers.Bounds(OpenLayers.Element.getStyle(this.contentDiv,"padding-left"),OpenLayers.Element.getStyle(this.contentDiv,"padding-bottom"),OpenLayers.Element.getStyle(this.contentDiv,"padding-right"),OpenLayers.Element.getStyle(this.contentDiv,
"padding-top")),this.div.parentNode==document.body&&(document.body.removeChild(this.div),this.div.style.display=""));return a},addCloseBox:function(a){this.closeDiv=OpenLayers.Util.createDiv(this.id+"_close",null,{w:17,h:17});this.closeDiv.className="olPopupCloseBox";var b=this.getContentDivPadding();this.closeDiv.style.right=b.right+"px";this.closeDiv.style.top=b.top+"px";this.groupDiv.appendChild(this.closeDiv);a=a||function(a){this.hide();OpenLayers.Event.stop(a)};OpenLayers.Event.observe(this.closeDiv,
"touchend",OpenLayers.Function.bindAsEventListener(a,this));OpenLayers.Event.observe(this.closeDiv,"click",OpenLayers.Function.bindAsEventListener(a,this))},panIntoView:function(){var a=this.map.getSize(),b=this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(parseInt(this.div.style.left),parseInt(this.div.style.top))),c=b.clone();b.x<this.map.paddingForPopups.left?c.x=this.map.paddingForPopups.left:b.x+this.size.w>a.w-this.map.paddingForPopups.right&&(c.x=a.w-this.map.paddingForPopups.right-this.size.w);
b.y<this.map.paddingForPopups.top?c.y=this.map.paddingForPopups.top:b.y+this.size.h>a.h-this.map.paddingForPopups.bottom&&(c.y=a.h-this.map.paddingForPopups.bottom-this.size.h);this.map.pan(b.x-c.x,b.y-c.y)},registerEvents:function(){this.events=new OpenLayers.Events(this,this.div,null,!0);this.events.on({mousedown:this.onmousedown,mousemove:this.onmousemove,mouseup:this.onmouseup,click:this.onclick,mouseout:this.onmouseout,dblclick:this.ondblclick,touchstart:function(a){OpenLayers.Event.stop(a,!0)},
scope:this})},onmousedown:function(a){this.mousedown=!0;OpenLayers.Event.stop(a,!0)},onmousemove:function(a){this.mousedown&&OpenLayers.Event.stop(a,!0)},onmouseup:function(a){this.mousedown&&(this.mousedown=!1,OpenLayers.Event.stop(a,!0))},onclick:function(a){OpenLayers.Event.stop(a,!0)},onmouseout:function(a){this.mousedown=!1},ondblclick:function(a){OpenLayers.Event.stop(a,!0)},CLASS_NAME:"OpenLayers.Popup"});OpenLayers.Popup.WIDTH=200;OpenLayers.Popup.HEIGHT=200;OpenLayers.Popup.COLOR="white";
OpenLayers.Popup.OPACITY=1;OpenLayers.Popup.BORDER="0px";OpenLayers.Control.ScaleLine=OpenLayers.Class(OpenLayers.Control,{maxWidth:100,topOutUnits:"km",topInUnits:"m",bottomOutUnits:"mi",bottomInUnits:"ft",eTop:null,eBottom:null,geodesic:!1,draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.eTop||(this.eTop=document.createElement("div"),this.eTop.className=this.displayClass+"Top",this.div.appendChild(this.eTop),this.eTop.style.visibility=""==this.topOutUnits||""==this.topInUnits?"hidden":"visible",this.eBottom=document.createElement("div"),
this.eBottom.className=this.displayClass+"Bottom",this.div.appendChild(this.eBottom),this.eBottom.style.visibility=""==this.bottomOutUnits||""==this.bottomInUnits?"hidden":"visible");this.map.events.register("moveend",this,this.update);this.update();return this.div},getBarLen:function(a){var b=parseInt(Math.log(a)/Math.log(10)),b=Math.pow(10,b);a=parseInt(a/b);return(5<a?5:2<a?2:1)*b},update:function(){var a=this.map.getResolution();if(a){var b=this.map.getUnits(),c=OpenLayers.INCHES_PER_UNIT,d=this.maxWidth*
a*c[b],e=1;!0===this.geodesic&&(e=(this.map.getGeodesicPixelSize().w||1E-6)*this.maxWidth/(d/c.km),d*=e);var f,g;1E5<d?(f=this.topOutUnits,g=this.bottomOutUnits):(f=this.topInUnits,g=this.bottomInUnits);var h=d/c[f],k=d/c[g],d=this.getBarLen(h),l=this.getBarLen(k),h=d/c[b]*c[f],k=l/c[b]*c[g],b=h/a/e,a=k/a/e;"visible"==this.eBottom.style.visibility&&(this.eBottom.style.width=Math.round(a)+"px",this.eBottom.innerHTML=l+" "+g);"visible"==this.eTop.style.visibility&&(this.eTop.style.width=Math.round(b)+
"px",this.eTop.innerHTML=d+" "+f)}},CLASS_NAME:"OpenLayers.Control.ScaleLine"});OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(a,b,c,d){this.url=a;this.size=b||{w:20,h:20};this.offset=c||{x:-(this.size.w/2),y:-(this.size.h/2)};this.calculateOffset=d;a=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(a)},destroy:function(){this.erase();OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null},clone:function(){return new OpenLayers.Icon(this.url,
this.size,this.offset,this.calculateOffset)},setSize:function(a){null!=a&&(this.size=a);this.draw()},setUrl:function(a){null!=a&&(this.url=a);this.draw()},draw:function(a){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(a);return this.imageDiv},erase:function(){null!=this.imageDiv&&null!=this.imageDiv.parentNode&&OpenLayers.Element.remove(this.imageDiv)},setOpacity:function(a){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,
null,null,null,a)},moveTo:function(a){null!=a&&(this.px=a);null!=this.imageDiv&&(null==this.px?this.display(!1):(this.calculateOffset&&(this.offset=this.calculateOffset(this.size)),OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,{x:this.px.x+this.offset.x,y:this.px.y+this.offset.y})))},display:function(a){this.imageDiv.style.display=a?"":"none"},isDrawn:function(){return this.imageDiv&&this.imageDiv.parentNode&&11!=this.imageDiv.parentNode.nodeType},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(a,b){this.lonlat=a;var c=b?b:OpenLayers.Marker.defaultIcon();null==this.icon?this.icon=c:(this.icon.url=c.url,this.icon.size=c.size,this.icon.offset=c.offset,this.icon.calculateOffset=c.calculateOffset);this.events=new OpenLayers.Events(this,this.icon.imageDiv)},destroy:function(){this.erase();this.map=null;this.events.destroy();this.events=null;null!=this.icon&&(this.icon.destroy(),this.icon=null)},
draw:function(a){return this.icon.draw(a)},erase:function(){null!=this.icon&&this.icon.erase()},moveTo:function(a){null!=a&&null!=this.icon&&this.icon.moveTo(a);this.lonlat=this.map.getLonLatFromLayerPx(a)},isDrawn:function(){return this.icon&&this.icon.isDrawn()},onScreen:function(){var a=!1;this.map&&(a=this.map.getExtent().containsLonLat(this.lonlat));return a},inflate:function(a){this.icon&&this.icon.setSize({w:this.icon.size.w*a,h:this.icon.size.h*a})},setOpacity:function(a){this.icon.setOpacity(a)},
setUrl:function(a){this.icon.setUrl(a)},display:function(a){this.icon.display(a)},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"),{w:21,h:25},{x:-10.5,y:-25})};OpenLayers.Layer.TileCache=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,format:"image/png",serverResolutions:null,initialize:function(a,b,c,d){this.layername=c;OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,{},d]);this.extension=this.format.split("/")[1].toLowerCase();this.extension="jpg"==this.extension?"jpeg":this.extension},clone:function(a){null==a&&(a=new OpenLayers.Layer.TileCache(this.name,this.url,this.layername,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
[a])},getURL:function(a){var b=this.getServerResolution(),c=this.maxExtent,d=this.tileSize,e=Math.round((a.left-c.left)/(b*d.w));a=Math.round((a.bottom-c.bottom)/(b*d.h));b=null!=this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,b):this.map.getZoom();e=[this.layername,OpenLayers.Number.zeroPad(b,2),OpenLayers.Number.zeroPad(parseInt(e/1E6),3),OpenLayers.Number.zeroPad(parseInt(e/1E3)%1E3,3),OpenLayers.Number.zeroPad(parseInt(e)%1E3,3),OpenLayers.Number.zeroPad(parseInt(a/1E6),
3),OpenLayers.Number.zeroPad(parseInt(a/1E3)%1E3,3),OpenLayers.Number.zeroPad(parseInt(a)%1E3,3)+"."+this.extension].join("/");b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(e,b));b="/"==b.charAt(b.length-1)?b:b+"/";return b+e},CLASS_NAME:"OpenLayers.Layer.TileCache"});OpenLayers.Strategy.Paging=OpenLayers.Class(OpenLayers.Strategy,{features:null,length:10,num:null,paging:!1,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a)this.layer.events.on({beforefeaturesadded:this.cacheFeatures,scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&(this.clearCache(),this.layer.events.un({beforefeaturesadded:this.cacheFeatures,scope:this}));return a},cacheFeatures:function(a){this.paging||(this.clearCache(),
this.features=a.features,this.pageNext(a))},clearCache:function(){if(this.features)for(var a=0;a<this.features.length;++a)this.features[a].destroy();this.num=this.features=null},pageCount:function(){return Math.ceil((this.features?this.features.length:0)/this.length)},pageNum:function(){return this.num},pageLength:function(a){a&&0<a&&(this.length=a);return this.length},pageNext:function(a){var b=!1;this.features&&(null===this.num&&(this.num=-1),b=this.page((this.num+1)*this.length,a));return b},pagePrevious:function(){var a=
!1;this.features&&(null===this.num&&(this.num=this.pageCount()),a=this.page((this.num-1)*this.length));return a},page:function(a,b){var c=!1;if(this.features&&0<=a&&a<this.features.length){var d=Math.floor(a/this.length);d!=this.num&&(this.paging=!0,c=this.features.slice(a,a+this.length),this.layer.removeFeatures(this.layer.features),this.num=d,b&&b.features?b.features=c:this.layer.addFeatures(c),this.paging=!1,c=!0)}return c},CLASS_NAME:"OpenLayers.Strategy.Paging"});OpenLayers.Control.DragFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,onStart:function(a,b){},onDrag:function(a,b){},onComplete:function(a,b){},onEnter:function(a){},onLeave:function(a){},documentDrag:!1,layer:null,feature:null,dragCallbacks:{},featureCallbacks:{},lastPixel:null,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.layer=a;this.handlers={drag:new OpenLayers.Handler.Drag(this,OpenLayers.Util.extend({down:this.downFeature,move:this.moveFeature,
up:this.upFeature,out:this.cancel,done:this.doneDragging},this.dragCallbacks),{documentDrag:this.documentDrag}),feature:new OpenLayers.Handler.Feature(this,this.layer,OpenLayers.Util.extend({click:this.clickFeature,clickout:this.clickoutFeature,over:this.overFeature,out:this.outFeature},this.featureCallbacks),{geometryTypes:this.geometryTypes})}},clickFeature:function(a){this.handlers.feature.touch&&(!this.over&&this.overFeature(a))&&(this.handlers.drag.dragstart(this.handlers.feature.evt),this.handlers.drag.stopDown=
!1)},clickoutFeature:function(a){this.handlers.feature.touch&&this.over&&(this.outFeature(a),this.handlers.drag.stopDown=!0)},destroy:function(){this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[])},activate:function(){return this.handlers.feature.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.handlers.drag.deactivate();this.handlers.feature.deactivate();this.feature=null;this.dragging=!1;this.lastPixel=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,
this.displayClass+"Over");return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},overFeature:function(a){var b=!1;this.handlers.drag.dragging?this.over=this.feature.id==a.id?!0:!1:(this.feature=a,this.handlers.drag.activate(),this.over=b=!0,OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass+"Over"),this.onEnter(a));return b},downFeature:function(a){this.lastPixel=a;this.onStart(this.feature,a)},moveFeature:function(a){var b=this.map.getResolution();this.feature.geometry.move(b*
(a.x-this.lastPixel.x),b*(this.lastPixel.y-a.y));this.layer.drawFeature(this.feature);this.lastPixel=a;this.onDrag(this.feature,a)},upFeature:function(a){this.over||this.handlers.drag.deactivate()},doneDragging:function(a){this.onComplete(this.feature,a)},outFeature:function(a){this.handlers.drag.dragging?this.feature.id==a.id&&(this.over=!1):(this.over=!1,this.handlers.drag.deactivate(),OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass+"Over"),this.onLeave(a),this.feature=null)},
cancel:function(){this.handlers.drag.deactivate();this.over=!1},setMap:function(a){this.handlers.drag.setMap(a);this.handlers.feature.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.DragFeature"});OpenLayers.Control.TransformFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,layer:null,preserveAspectRatio:!1,rotate:!0,feature:null,renderIntent:"temporary",rotationHandleSymbolizer:null,box:null,center:null,scale:1,ratio:1,rotation:0,handles:null,rotationHandles:null,dragControl:null,irregular:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.layer=a;this.rotationHandleSymbolizer||(this.rotationHandleSymbolizer={stroke:!1,pointRadius:10,fillOpacity:0,
cursor:"pointer"});this.createBox();this.createControl()},activate:function(){var a=!1;OpenLayers.Control.prototype.activate.apply(this,arguments)&&(this.dragControl.activate(),this.layer.addFeatures([this.box]),this.rotate&&this.layer.addFeatures(this.rotationHandles),this.layer.addFeatures(this.handles),a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Control.prototype.deactivate.apply(this,arguments)&&(this.layer.removeFeatures(this.handles),this.rotate&&this.layer.removeFeatures(this.rotationHandles),
this.layer.removeFeatures([this.box]),this.dragControl.deactivate(),a=!0);return a},setMap:function(a){this.dragControl.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},setFeature:function(a,b){b=OpenLayers.Util.applyDefaults(b,{rotation:0,scale:1,ratio:1});var c=this.rotation,d=this.center;OpenLayers.Util.extend(this,b);if(!1!==this.events.triggerEvent("beforesetfeature",{feature:a})){this.feature=a;this.activate();this._setfeature=!0;var e=this.feature.geometry.getBounds();this.box.move(e.getCenterLonLat());
this.box.geometry.rotate(-c,d);this._angle=0;this.rotation?(c=a.geometry.clone(),c.rotate(-this.rotation,this.center),c=new OpenLayers.Feature.Vector(c.getBounds().toGeometry()),c.geometry.rotate(this.rotation,this.center),this.box.geometry.rotate(this.rotation,this.center),this.box.move(c.geometry.getBounds().getCenterLonLat()),c=c.geometry.components[0].components[0].getBounds().getCenterLonLat()):c=new OpenLayers.LonLat(e.left,e.bottom);this.handles[0].move(c);delete this._setfeature;this.events.triggerEvent("setfeature",
{feature:a})}},unsetFeature:function(){this.active?this.deactivate():(this.feature=null,this.rotation=0,this.ratio=this.scale=1)},createBox:function(){var a=this;this.center=new OpenLayers.Geometry.Point(0,0);this.box=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([new OpenLayers.Geometry.Point(-1,-1),new OpenLayers.Geometry.Point(0,-1),new OpenLayers.Geometry.Point(1,-1),new OpenLayers.Geometry.Point(1,0),new OpenLayers.Geometry.Point(1,1),new OpenLayers.Geometry.Point(0,1),new OpenLayers.Geometry.Point(-1,
1),new OpenLayers.Geometry.Point(-1,0),new OpenLayers.Geometry.Point(-1,-1)]),null,"string"==typeof this.renderIntent?null:this.renderIntent);this.box.geometry.move=function(b,c){a._moving=!0;OpenLayers.Geometry.LineString.prototype.move.apply(this,arguments);a.center.move(b,c);delete a._moving};for(var b=function(a,b){OpenLayers.Geometry.Point.prototype.move.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.move(a,b);this._handle.geometry.move(a,b)},c=function(a,b,c){OpenLayers.Geometry.Point.prototype.resize.apply(this,
arguments);this._rotationHandle&&this._rotationHandle.geometry.resize(a,b,c);this._handle.geometry.resize(a,b,c)},d=function(a,b){OpenLayers.Geometry.Point.prototype.rotate.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.rotate(a,b);this._handle.geometry.rotate(a,b)},e=function(b,c){var d=this.x,e=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,b,c);if(!a._moving){var f=a.dragControl.handlers.drag.evt,g=!(!a._setfeature&&a.preserveAspectRatio)&&!(f&&f.shiftKey),
h=new OpenLayers.Geometry.Point(d,e),f=a.center;this.rotate(-a.rotation,f);h.rotate(-a.rotation,f);var k=this.x-f.x,l=this.y-f.y,m=k-(this.x-h.x),n=l-(this.y-h.y);a.irregular&&!a._setfeature&&(k-=(this.x-h.x)/2,l-=(this.y-h.y)/2);this.x=d;this.y=e;h=1;g?(l=1E-5>Math.abs(n)?1:l/n,h=(1E-5>Math.abs(m)?1:k/m)/l):(m=Math.sqrt(m*m+n*n),l=Math.sqrt(k*k+l*l)/m);a._moving=!0;a.box.geometry.rotate(-a.rotation,f);delete a._moving;a.box.geometry.resize(l,f,h);a.box.geometry.rotate(a.rotation,f);a.transformFeature({scale:l,
ratio:h});a.irregular&&!a._setfeature&&(k=f.clone(),k.x+=1E-5>Math.abs(d-f.x)?0:this.x-d,k.y+=1E-5>Math.abs(e-f.y)?0:this.y-e,a.box.geometry.move(this.x-d,this.y-e),a.transformFeature({center:k}))}},f=function(b,c){var d=this.x,e=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,b,c);if(!a._moving){var f=a.dragControl.handlers.drag.evt,f=f&&f.shiftKey?45:1,g=a.center,h=this.x-g.x,k=this.y-g.y;this.x=d;this.y=e;d=Math.atan2(k-c,h-b);d=Math.atan2(k,h)-d;d*=180/Math.PI;a._angle=(a._angle+d)%
360;d=a.rotation%f;if(Math.abs(a._angle)>=f||0!==d)d=Math.round(a._angle/f)*f-d,a._angle=0,a.box.geometry.rotate(d,g),a.transformFeature({rotation:d})}},g=Array(8),h=Array(4),k,l,m,n="sw s se e ne n nw w".split(" "),p=0;8>p;++p)k=this.box.geometry.components[p],l=new OpenLayers.Feature.Vector(k.clone(),{role:n[p]+"-resize"},"string"==typeof this.renderIntent?null:this.renderIntent),0==p%2&&(m=new OpenLayers.Feature.Vector(k.clone(),{role:n[p]+"-rotate"},"string"==typeof this.rotationHandleSymbolizer?
null:this.rotationHandleSymbolizer),m.geometry.move=f,k._rotationHandle=m,h[p/2]=m),k.move=b,k.resize=c,k.rotate=d,l.geometry.move=e,k._handle=l,g[p]=l;this.rotationHandles=h;this.handles=g},createControl:function(){var a=this;this.dragControl=new OpenLayers.Control.DragFeature(this.layer,{documentDrag:!0,moveFeature:function(b){this.feature===a.feature&&(this.feature=a.box);OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this,arguments)},onDrag:function(b,c){b===a.box&&a.transformFeature({center:a.center})},
onStart:function(b,c){var d=!a.geometryTypes||-1!==OpenLayers.Util.indexOf(a.geometryTypes,b.geometry.CLASS_NAME),e=OpenLayers.Util.indexOf(a.handles,b),e=e+OpenLayers.Util.indexOf(a.rotationHandles,b);b!==a.feature&&(b!==a.box&&-2==e&&d)&&a.setFeature(b)},onComplete:function(b,c){a.events.triggerEvent("transformcomplete",{feature:a.feature})}})},drawHandles:function(){for(var a=this.layer,b=0;8>b;++b)this.rotate&&0===b%2&&a.drawFeature(this.rotationHandles[b/2],this.rotationHandleSymbolizer),a.drawFeature(this.handles[b],
this.renderIntent)},transformFeature:function(a){if(!this._setfeature){this.scale*=a.scale||1;this.ratio*=a.ratio||1;var b=this.rotation;this.rotation=(this.rotation+(a.rotation||0))%360;if(!1!==this.events.triggerEvent("beforetransform",a)){var c=this.feature,d=c.geometry,e=this.center;d.rotate(-b,e);a.scale||a.ratio?d.resize(a.scale,e,a.ratio):a.center&&c.move(a.center.getBounds().getCenterLonLat());d.rotate(this.rotation,e);this.layer.drawFeature(c);c.toState(OpenLayers.State.UPDATE);this.events.triggerEvent("transform",
a)}}this.layer.drawFeature(this.box,this.renderIntent);this.drawHandles()},destroy:function(){for(var a,b=0;8>b;++b)a=this.box.geometry.components[b],a._handle.destroy(),a._handle=null,a._rotationHandle&&a._rotationHandle.destroy(),a._rotationHandle=null;this.rotationHandles=this.rotationHandleSymbolizer=this.handles=this.feature=this.center=null;this.box.destroy();this.layer=this.box=null;this.dragControl.destroy();this.dragControl=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},
CLASS_NAME:"OpenLayers.Control.TransformFeature"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:"olHandlerBoxZoomBox",boxOffsets:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.dragHandler=new OpenLayers.Handler.Drag(this,{down:this.startBox,move:this.moveBox,out:this.removeBox,up:this.endBox},{keyMask:this.keyMask})},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.dragHandler&&(this.dragHandler.destroy(),this.dragHandler=
null)},setMap:function(a){OpenLayers.Handler.prototype.setMap.apply(this,arguments);this.dragHandler&&this.dragHandler.setMap(a)},startBox:function(a){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv("zoomBox",{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE.Popup-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox")},moveBox:function(a){var b=this.dragHandler.start.x,
c=this.dragHandler.start.y,d=Math.abs(b-a.x),e=Math.abs(c-a.y),f=this.getBoxOffsets();this.zoomBox.style.width=d+f.width+1+"px";this.zoomBox.style.height=e+f.height+1+"px";this.zoomBox.style.left=(a.x<b?b-d-f.left:b-f.left)+"px";this.zoomBox.style.top=(a.y<c?c-e-f.top:c-f.top)+"px"},endBox:function(a){var b;if(5<Math.abs(this.dragHandler.start.x-a.x)||5<Math.abs(this.dragHandler.start.y-a.y)){var c=this.dragHandler.start;b=Math.min(c.y,a.y);var d=Math.max(c.y,a.y),e=Math.min(c.x,a.x);a=Math.max(c.x,
a.x);b=new OpenLayers.Bounds(e,d,a,b)}else b=this.dragHandler.start.clone();this.removeBox();this.callback("done",[b])},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.boxOffsets=this.zoomBox=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox")},activate:function(){return OpenLayers.Handler.prototype.activate.apply(this,arguments)?(this.dragHandler.activate(),!0):!1},deactivate:function(){return OpenLayers.Handler.prototype.deactivate.apply(this,arguments)?
(this.dragHandler.deactivate()&&this.zoomBox&&this.removeBox(),!0):!1},getBoxOffsets:function(){if(!this.boxOffsets){var a=document.createElement("div");a.style.position="absolute";a.style.border="1px solid black";a.style.width="3px";document.body.appendChild(a);var b=3==a.clientWidth;document.body.removeChild(a);var a=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width")),c=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width")),d=parseInt(OpenLayers.Element.getStyle(this.zoomBox,
"border-top-width")),e=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:a,right:c,top:d,bottom:e,width:!1===b?a+c:0,height:!1===b?d+e:0}}return this.boxOffsets},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:!1,keyMask:null,alwaysZoom:!1,zoomOnClick:!0,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask})},zoomBox:function(a){if(a instanceof OpenLayers.Bounds){var b,c=a.getCenterPixel();if(this.out){b=Math.min(this.map.size.h/(a.bottom-a.top),this.map.size.w/(a.right-a.left));var d=this.map.getExtent(),e=this.map.getLonLatFromPixel(c),f=e.lon-d.getWidth()/
2*b;a=e.lon+d.getWidth()/2*b;var g=e.lat-d.getHeight()/2*b;b=e.lat+d.getHeight()/2*b;b=new OpenLayers.Bounds(f,g,a,b)}else f=this.map.getLonLatFromPixel({x:a.left,y:a.bottom}),a=this.map.getLonLatFromPixel({x:a.right,y:a.top}),b=new OpenLayers.Bounds(f.lon,f.lat,a.lon,a.lat);f=this.map.getZoom();g=this.map.getSize();a=g.w/2;g=g.h/2;b=this.map.getZoomForExtent(b);d=this.map.getResolution();e=this.map.getResolutionForZoom(b);d==e?this.map.setCenter(this.map.getLonLatFromPixel(c)):this.map.zoomTo(b,
{x:(d*c.x-e*a)/(d-e),y:(d*c.y-e*g)/(d-e)});f==this.map.getZoom()&&!0==this.alwaysZoom&&this.map.zoomTo(f+(this.out?-1:1))}else this.zoomOnClick&&(this.out?this.map.zoomTo(this.map.getZoom()-1,a):this.map.zoomTo(this.map.getZoom()+1,a))},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:!1,interval:0,documentDrag:!1,kinetic:null,enableKinetic:!0,kineticInterval:10,draw:function(){if(this.enableKinetic&&OpenLayers.Kinetic){var a={interval:this.kineticInterval};"object"===typeof this.enableKinetic&&(a=OpenLayers.Util.extend(a,this.enableKinetic));this.kinetic=new OpenLayers.Kinetic(a)}this.handler=new OpenLayers.Handler.Drag(this,{move:this.panMap,done:this.panMapDone,down:this.panMapStart},
{interval:this.interval,documentDrag:this.documentDrag})},panMapStart:function(){this.kinetic&&this.kinetic.begin()},panMap:function(a){this.kinetic&&this.kinetic.update(a);this.panned=!0;this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!0,animate:!1})},panMapDone:function(a){if(this.panned){var b=null;this.kinetic&&(b=this.kinetic.end(a));this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!!b,animate:!1});if(b){var c=this;this.kinetic.move(b,function(a,b,
f){c.map.pan(a,b,{dragging:!f,animate:!1})})}this.panned=!1}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,documentDrag:!1,zoomBox:null,zoomBoxEnabled:!0,zoomWheelEnabled:!0,mouseWheelOptions:null,handleRightClicks:!1,zoomBoxKeyMask:OpenLayers.Handler.MOD_SHIFT,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null;
this.zoomBox&&this.zoomBox.destroy();this.zoomBox=null;this.pinchZoom&&this.pinchZoom.destroy();this.pinchZoom=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){this.dragPan.activate();this.zoomWheelEnabled&&this.handlers.wheel.activate();this.handlers.click.activate();this.zoomBoxEnabled&&this.zoomBox.activate();this.pinchZoom&&this.pinchZoom.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.pinchZoom&&this.pinchZoom.deactivate();
this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},draw:function(){this.handleRightClicks&&(this.map.viewPortDiv.oncontextmenu=OpenLayers.Function.False);this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.defaultClick,dblclick:this.defaultDblClick,dblrightclick:this.defaultDblRightClick},{"double":!0,stopDouble:!0});this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,
documentDrag:this.documentDrag},this.dragPanOptions));this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:this.zoomBoxKeyMask});this.dragPan.draw();this.zoomBox.draw();this.handlers.wheel=new OpenLayers.Handler.MouseWheel(this,{up:this.wheelUp,down:this.wheelDown},OpenLayers.Util.extend(this.map.fractionalZoom?{}:{cumulative:!1,interval:50,maxDelta:6},this.mouseWheelOptions));OpenLayers.Control.PinchZoom&&(this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},
this.pinchZoomOptions)))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&&this.map.zoomOut()},defaultDblClick:function(a){this.map.zoomTo(this.map.zoom+1,a.xy)},defaultDblRightClick:function(a){this.map.zoomTo(this.map.zoom-1,a.xy)},wheelChange:function(a,b){this.map.fractionalZoom||(b=Math.round(b));var c=this.map.getZoom(),d;d=Math.max(c+b,0);d=Math.min(d,this.map.getNumZoomLevels());d!==c&&this.map.zoomTo(d,a.xy)},wheelUp:function(a,b){this.wheelChange(a,b||1)},wheelDown:function(a,
b){this.wheelChange(a,b||-1)},disableZoomBox:function(){this.zoomBoxEnabled=!1;this.zoomBox.deactivate()},enableZoomBox:function(){this.zoomBoxEnabled=!0;this.active&&this.zoomBox.activate()},disableZoomWheel:function(){this.zoomWheelEnabled=!1;this.handlers.wheel.deactivate()},enableZoomWheel:function(){this.zoomWheelEnabled=!0;this.active&&this.handlers.wheel.activate()},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Control.DrawFeature=OpenLayers.Class(OpenLayers.Control,{layer:null,callbacks:null,multi:!1,featureAdded:function(){},initialize:function(a,b,c){OpenLayers.Control.prototype.initialize.apply(this,[c]);this.callbacks=OpenLayers.Util.extend({done:this.drawFeature,modify:function(a,b){this.layer.events.triggerEvent("sketchmodified",{vertex:a,feature:b})},create:function(a,b){this.layer.events.triggerEvent("sketchstarted",{vertex:a,feature:b})}},this.callbacks);this.layer=a;this.handlerOptions=
this.handlerOptions||{};this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{renderers:a.renderers,rendererOptions:a.rendererOptions});"multi"in this.handlerOptions||(this.handlerOptions.multi=this.multi);if(a=this.layer.styleMap&&this.layer.styleMap.styles.temporary)this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":a})});this.handler=new b(this,this.callbacks,this.handlerOptions)},
drawFeature:function(a){a=new OpenLayers.Feature.Vector(a);!1!==this.layer.events.triggerEvent("sketchcomplete",{feature:a})&&(a.state=OpenLayers.State.INSERT,this.layer.addFeatures([a]),this.featureAdded(a),this.events.triggerEvent("featureadded",{feature:a}))},insertXY:function(a,b){this.handler&&this.handler.line&&this.handler.insertXY(a,b)},insertDeltaXY:function(a,b){this.handler&&this.handler.line&&this.handler.insertDeltaXY(a,b)},insertDirectionLength:function(a,b){this.handler&&this.handler.line&&
this.handler.insertDirectionLength(a,b)},insertDeflectionLength:function(a,b){this.handler&&this.handler.line&&this.handler.insertDeflectionLength(a,b)},undo:function(){return this.handler.undo&&this.handler.undo()},redo:function(){return this.handler.redo&&this.handler.redo()},finishSketch:function(){this.handler.finishGeometry()},cancel:function(){this.handler.cancel()},CLASS_NAME:"OpenLayers.Control.DrawFeature"});OpenLayers.Handler.Polygon=OpenLayers.Class(OpenLayers.Handler.Path,{holeModifier:null,drawingHole:!1,polygon:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LinearRing([this.point.geometry]));this.polygon=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([this.line.geometry]));this.callback("create",[this.point.geometry,
this.getSketch()]);this.point.geometry.clearBounds();this.layer.addFeatures([this.polygon,this.point],{silent:!0})},addPoint:function(a){if(!this.drawingHole&&this.holeModifier&&this.evt&&this.evt[this.holeModifier])for(var b=this.point.geometry,c=this.control.layer.features,d,e=c.length-1;0<=e;--e)if(d=c[e].geometry,(d instanceof OpenLayers.Geometry.Polygon||d instanceof OpenLayers.Geometry.MultiPolygon)&&d.intersects(b)){b=c[e];this.control.layer.removeFeatures([b],{silent:!0});this.control.layer.events.registerPriority("sketchcomplete",
this,this.finalizeInteriorRing);this.control.layer.events.registerPriority("sketchmodified",this,this.enforceTopology);b.geometry.addComponent(this.line.geometry);this.polygon=b;this.drawingHole=!0;break}OpenLayers.Handler.Path.prototype.addPoint.apply(this,arguments)},getCurrentPointIndex:function(){return this.line.geometry.components.length-2},enforceTopology:function(a){a=a.vertex;var b=this.line.geometry.components;this.polygon.geometry.intersects(a)||(b=b[b.length-3],a.x=b.x,a.y=b.y)},finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-
2]);this.removePoint();this.finalize()},finalizeInteriorRing:function(){var a=this.line.geometry,b=0!==a.getArea();if(b){for(var c=this.polygon.geometry.components,d=c.length-2;0<=d;--d)if(a.intersects(c[d])){b=!1;break}if(b)a:for(d=c.length-2;0<d;--d)for(var e=c[d].components,f=0,g=e.length;f<g;++f)if(a.containsPoint(e[f])){b=!1;break a}}b?this.polygon.state!==OpenLayers.State.INSERT&&(this.polygon.state=OpenLayers.State.UPDATE):this.polygon.geometry.removeComponent(a);this.restoreFeature();return!1},
cancel:function(){this.drawingHole&&(this.polygon.geometry.removeComponent(this.line.geometry),this.restoreFeature(!0));return OpenLayers.Handler.Path.prototype.cancel.apply(this,arguments)},restoreFeature:function(a){this.control.layer.events.unregister("sketchcomplete",this,this.finalizeInteriorRing);this.control.layer.events.unregister("sketchmodified",this,this.enforceTopology);this.layer.removeFeatures([this.polygon],{silent:!0});this.control.layer.addFeatures([this.polygon],{silent:!0});this.drawingHole=
!1;a||this.control.layer.events.triggerEvent("sketchcomplete",{feature:this.polygon})},destroyFeature:function(a){OpenLayers.Handler.Path.prototype.destroyFeature.call(this,a);this.polygon=null},drawFeature:function(){this.layer.drawFeature(this.polygon,this.style);this.layer.drawFeature(this.point,this.style)},getSketch:function(){return this.polygon},getGeometry:function(){var a=this.polygon&&this.polygon.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiPolygon([a]));return a},CLASS_NAME:"OpenLayers.Handler.Polygon"});OpenLayers.Control.EditingToolbar=OpenLayers.Class(OpenLayers.Control.Panel,{citeCompliant:!1,initialize:function(a,b){OpenLayers.Control.Panel.prototype.initialize.apply(this,[b]);this.addControls([new OpenLayers.Control.Navigation]);var c=[new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Point,{displayClass:"olControlDrawFeaturePoint",handlerOptions:{citeCompliant:this.citeCompliant}}),new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Path,{displayClass:"olControlDrawFeaturePath",handlerOptions:{citeCompliant:this.citeCompliant}}),
new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Polygon,{displayClass:"olControlDrawFeaturePolygon",handlerOptions:{citeCompliant:this.citeCompliant}})];this.addControls(c)},draw:function(){var a=OpenLayers.Control.Panel.prototype.draw.apply(this,arguments);null===this.defaultControl&&(this.defaultControl=this.controls[0]);return a},CLASS_NAME:"OpenLayers.Control.EditingToolbar"});OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);a&&(this.layer.events.on({moveend:this.update,refresh:this.update,visibilitychanged:this.update,scope:this}),this.update());return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.layer.events.un({moveend:this.update,refresh:this.update,visibilitychanged:this.update,
scope:this});return a},update:function(a){var b=this.getMapBounds();null!==b&&(a&&a.force||this.layer.visibility&&this.layer.calculateInRange()&&this.invalidBounds(b))&&(this.calculateBounds(b),this.resolution=this.layer.map.getResolution(),this.triggerRead(a))},getMapBounds:function(){if(null===this.layer.map)return null;var a=this.layer.map.getExtent();a&&!this.layer.projection.equals(this.layer.map.getProjectionObject())&&(a=a.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection));
return a},invalidBounds:function(a){a||(a=this.getMapBounds());a=!this.bounds||!this.bounds.containsBounds(a);!a&&this.resFactor&&(a=this.resolution/this.layer.map.getResolution(),a=a>=this.resFactor||a<=1/this.resFactor);return a},calculateBounds:function(a){a||(a=this.getMapBounds());var b=a.getCenterLonLat(),c=a.getWidth()*this.ratio;a=a.getHeight()*this.ratio;this.bounds=new OpenLayers.Bounds(b.lon-c/2,b.lat-a/2,b.lon+c/2,b.lat+a/2)},triggerRead:function(a){!this.response||a&&!0===a.noAbort||
(this.layer.protocol.abort(this.response),this.layer.events.triggerEvent("loadend"));var b={filter:this.createFilter()};this.layer.events.triggerEvent("loadstart",b);this.response=this.layer.protocol.read(OpenLayers.Util.applyDefaults({filter:b.filter,callback:this.merge,scope:this},a))},createFilter:function(){var a=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,value:this.bounds,projection:this.layer.projection});this.layer.filter&&(a=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,
filters:[this.layer.filter,a]}));return a},merge:function(a){this.layer.destroyFeatures();if(a.success()){var b=a.features;if(b&&0<b.length){var c=this.layer.projection,d=this.layer.map.getProjectionObject();if(!d.equals(c))for(var e,f=0,g=b.length;f<g;++f)(e=b[f].geometry)&&e.transform(c,d);this.layer.addFeatures(b)}}else this.bounds=null;this.response=null;this.layer.events.triggerEvent("loadend",{response:a})},CLASS_NAME:"OpenLayers.Strategy.BBOX"});OpenLayers.Layer.WorldWind=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{},isBaseLayer:!0,lzd:null,zoomLevels:null,initialize:function(a,b,c,d,e,f){this.lzd=c;this.zoomLevels=d;c=[];c.push(a,b,e,f);OpenLayers.Layer.Grid.prototype.initialize.apply(this,c);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS)},getZoom:function(){var a=this.map.getZoom();this.map.getMaxExtent();return a-=Math.log(this.maxResolution/(this.lzd/512))/Math.log(2)},getURL:function(a){a=this.adjustBounds(a);
var b=this.getZoom(),c=this.map.getMaxExtent(),d=this.lzd/Math.pow(2,this.getZoom()),e=Math.floor((a.left-c.left)/d);a=Math.floor((a.bottom-c.bottom)/d);return this.map.getResolution()<=this.lzd/512&&this.getZoom()<=this.zoomLevels?this.getFullRequestString({L:b,X:e,Y:a}):OpenLayers.Util.getImageLocation("blank.gif")},CLASS_NAME:"OpenLayers.Layer.WorldWind"});OpenLayers.Protocol.CSW=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.CSW.DEFAULTS);var b=OpenLayers.Protocol.CSW["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSW version: "+a.version;return new b(a)};OpenLayers.Protocol.CSW.DEFAULTS={version:"2.0.2"};OpenLayers.Format.WMTSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",yx:{"urn:ogc:def:crs:EPSG::4326":!0},createLayer:function(a,b){if(!("layer"in b))throw Error("Missing property 'layer' in configuration.");for(var c=a.contents,d,e=0,f=c.layers.length;e<f;++e)if(c.layers[e].identifier===b.layer){d=c.layers[e];break}if(!d)throw Error("Layer not found");var g=b.format;!g&&(d.formats&&d.formats.length)&&(g=d.formats[0]);var h;b.matrixSet?h=c.tileMatrixSets[b.matrixSet]:
1<=d.tileMatrixSetLinks.length&&(h=c.tileMatrixSets[d.tileMatrixSetLinks[0].tileMatrixSet]);if(!h)throw Error("matrixSet not found");for(var k,e=0,f=d.styles.length;e<f&&(k=d.styles[e],!k.isDefault);++e);c=b.requestEncoding;if(!c&&(c="KVP",a.operationsMetadata.GetTile.dcp.http)){var l=a.operationsMetadata.GetTile.dcp.http;l.get[0].constraints&&(l=l.get[0].constraints.GetEncoding.allowedValues,l.KVP||!l.REST&&!l.RESTful||(c="REST"))}var l=[],m=b.params||{};delete b.params;for(var n=0,p=d.dimensions.length;n<
p;n++){var q=d.dimensions[n];l.push(q.identifier);m.hasOwnProperty(q.identifier)||(m[q.identifier]=q["default"])}var n=b.projection||h.supportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/,"$1:$3"),p=b.units||("EPSG:4326"===n?"degrees":"m"),q=[],r;for(r in h.matrixIds)h.matrixIds.hasOwnProperty(r)&&q.push(2.8E-4*h.matrixIds[r].scaleDenominator/OpenLayers.METERS_PER_INCH/OpenLayers.INCHES_PER_UNIT[p]);if("REST"===c&&d.resourceUrls){r=[];for(var f=0,s=d.resourceUrls.length;f<s;++f)e=d.resourceUrls[f],
e.format===g&&"tile"===e.resourceType&&r.push(e.template)}else{s=a.operationsMetadata.GetTile.dcp.http.get;r=[];for(var t,e=0,f=s.length;e<f;e++)t=s[e].constraints,(!t||t&&t.GetEncoding.allowedValues[c])&&r.push(s[e].url)}return new OpenLayers.Layer.WMTS(OpenLayers.Util.applyDefaults(b,{url:r,requestEncoding:c,name:d.title,style:k.identifier,format:g,matrixIds:h.matrixIds,matrixSet:h.identifier,projection:n,units:p,resolutions:!1===b.isBaseLayer?void 0:q,serverResolutions:q,tileFullExtent:h.bounds,
dimensions:l,params:m}))},CLASS_NAME:"OpenLayers.Format.WMTSCapabilities"});OpenLayers.Layer.Google.v3={DEFAULTS:{sphericalMercator:!0,projection:"EPSG:900913"},animationEnabled:!0,loadMapObject:function(){this.type||(this.type=google.maps.MapTypeId.ROADMAP);var a,b=OpenLayers.Layer.Google.cache[this.map.id];b?(a=b.mapObject,++b.count):(a=this.map.getCenter(),b=document.createElement("div"),b.className="olForeignContainer",b.style.width="100%",b.style.height="100%",a=new google.maps.Map(b,{center:a?new google.maps.LatLng(a.lat,a.lon):new google.maps.LatLng(0,0),zoom:this.map.getZoom()||
0,mapTypeId:this.type,disableDefaultUI:!0,keyboardShortcuts:!1,draggable:!1,disableDoubleClickZoom:!0,scrollwheel:!1,streetViewControl:!1}),b=document.createElement("div"),b.style.width="100%",b.style.height="100%",a.controls[google.maps.ControlPosition.TOP_LEFT].push(b),b={googleControl:b,mapObject:a,count:1},OpenLayers.Layer.Google.cache[this.map.id]=b);this.mapObject=a;this.setGMapVisibility(this.visibility)},onMapResize:function(){this.visibility&&google.maps.event.trigger(this.mapObject,"resize")},
setGMapVisibility:function(a){var b=OpenLayers.Layer.Google.cache[this.map.id],c=this.map;if(b){for(var d=this.type,e=c.layers,f,g=e.length-1;0<=g;--g)if(f=e[g],f instanceof OpenLayers.Layer.Google&&!0===f.visibility&&!0===f.inRange){d=f.type;a=!0;break}e=this.mapObject.getDiv();if(!0===a){if(e.parentNode!==c.div)if(b.rendered)c.div.appendChild(e),b.googleControl.appendChild(c.viewPortDiv),google.maps.event.trigger(this.mapObject,"resize");else{var h=this;google.maps.event.addListenerOnce(this.mapObject,
"tilesloaded",function(){b.rendered=!0;h.setGMapVisibility(h.getVisibility());h.moveTo(h.map.getCenter())})}this.mapObject.setMapTypeId(d)}else b.googleControl.hasChildNodes()&&(c.div.appendChild(c.viewPortDiv),c.div.removeChild(e))}},getMapContainer:function(){return this.mapObject.getDiv()},getMapObjectBoundsFromOLBounds:function(a){var b=null;null!=a&&(b=this.sphericalMercator?this.inverseMercator(a.bottom,a.left):new OpenLayers.LonLat(a.bottom,a.left),a=this.sphericalMercator?this.inverseMercator(a.top,
a.right):new OpenLayers.LonLat(a.top,a.right),b=new google.maps.LatLngBounds(new google.maps.LatLng(b.lat,b.lon),new google.maps.LatLng(a.lat,a.lon)));return b},getMapObjectLonLatFromMapObjectPixel:function(a){var b=this.map.getSize(),c=this.getLongitudeFromMapObjectLonLat(this.mapObject.center),d=this.getLatitudeFromMapObjectLonLat(this.mapObject.center),e=this.map.getResolution();a=new OpenLayers.LonLat(c+(a.x-b.w/2)*e,d-(a.y-b.h/2)*e);this.wrapDateLine&&(a=a.wrapDateLine(this.maxExtent));return this.getMapObjectLonLatFromLonLat(a.lon,
a.lat)},getMapObjectPixelFromMapObjectLonLat:function(a){var b=this.getLongitudeFromMapObjectLonLat(a);a=this.getLatitudeFromMapObjectLonLat(a);var c=this.map.getResolution(),d=this.map.getExtent();return this.getMapObjectPixelFromXY(1/c*(b-d.left),1/c*(d.top-a))},setMapObjectCenter:function(a,b){if(!1===this.animationEnabled&&b!=this.mapObject.zoom){var c=this.getMapContainer();google.maps.event.addListenerOnce(this.mapObject,"idle",function(){c.style.visibility=""});c.style.visibility="hidden"}this.mapObject.setOptions({center:a,
zoom:b})},getMapObjectZoomFromMapObjectBounds:function(a){return this.mapObject.getBoundsZoomLevel(a)},getMapObjectLonLatFromLonLat:function(a,b){var c;this.sphericalMercator?(c=this.inverseMercator(a,b),c=new google.maps.LatLng(c.lat,c.lon)):c=new google.maps.LatLng(b,a);return c},getMapObjectPixelFromXY:function(a,b){return new google.maps.Point(a,b)}};OpenLayers.Format.WPSDescribeProcess=OpenLayers.Class(OpenLayers.Format.XML,{VERSION:"1.0.0",namespaces:{wps:"http://www.opengis.net/wps/1.0.0",ows:"http://www.opengis.net/ows/1.1",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd",defaultPrefix:"wps",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,
[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{wps:{ProcessDescriptions:function(a,b){b.processDescriptions={};this.readChildNodes(a,b.processDescriptions)},ProcessDescription:function(a,b){var c={processVersion:this.getAttributeNS(a,this.namespaces.wps,"processVersion"),statusSupported:"true"===a.getAttribute("statusSupported"),storeSupported:"true"===a.getAttribute("storeSupported")};this.readChildNodes(a,c);b[c.identifier]=c},DataInputs:function(a,
b){b.dataInputs=[];this.readChildNodes(a,b.dataInputs)},ProcessOutputs:function(a,b){b.processOutputs=[];this.readChildNodes(a,b.processOutputs)},Output:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)},ComplexOutput:function(a,b){b.complexOutput={};this.readChildNodes(a,b.complexOutput)},LiteralOutput:function(a,b){b.literalOutput={};this.readChildNodes(a,b.literalOutput)},Input:function(a,b){var c={maxOccurs:parseInt(a.getAttribute("maxOccurs")),minOccurs:parseInt(a.getAttribute("minOccurs"))};
this.readChildNodes(a,c);b.push(c)},BoundingBoxData:function(a,b){b.boundingBoxData={};this.readChildNodes(a,b.boundingBoxData)},CRS:function(a,b){b.CRSs||(b.CRSs={});b.CRSs[this.getChildValue(a)]=!0},LiteralData:function(a,b){b.literalData={};this.readChildNodes(a,b.literalData)},ComplexData:function(a,b){b.complexData={};this.readChildNodes(a,b.complexData)},Default:function(a,b){b["default"]={};this.readChildNodes(a,b["default"])},Supported:function(a,b){b.supported={};this.readChildNodes(a,b.supported)},
Format:function(a,b){var c={};this.readChildNodes(a,c);b.formats||(b.formats={});b.formats[c.mimeType]=!0},MimeType:function(a,b){b.mimeType=this.getChildValue(a)}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WPSDescribeProcess"});OpenLayers.Format.WKT=OpenLayers.Class(OpenLayers.Format,{initialize:function(a){this.regExes={typeStr:/^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,spaces:/\s+/,parenComma:/\)\s*,\s*\(/,doubleParenComma:/\)\s*\)\s*,\s*\(\s*\(/,trimParens:/^\s*\(?(.*?)\)?\s*$/};OpenLayers.Format.prototype.initialize.apply(this,[a])},read:function(a){var b,c;a=a.replace(/[\n\r]/g," ");if(c=this.regExes.typeStr.exec(a))if(a=c[1].toLowerCase(),c=c[2],this.parse[a]&&(b=this.parse[a].apply(this,[c])),this.internalProjection&&this.externalProjection)if(b&&
"OpenLayers.Feature.Vector"==b.CLASS_NAME)b.geometry.transform(this.externalProjection,this.internalProjection);else if(b&&"geometrycollection"!=a&&"object"==typeof b)for(a=0,c=b.length;a<c;a++)b[a].geometry.transform(this.externalProjection,this.internalProjection);return b},write:function(a){var b,c;a.constructor==Array?c=!0:(a=[a],c=!1);var d=[];c&&d.push("GEOMETRYCOLLECTION(");for(var e=0,f=a.length;e<f;++e)c&&0<e&&d.push(","),b=a[e].geometry,d.push(this.extractGeometry(b));c&&d.push(")");return d.join("")},
extractGeometry:function(a){var b=a.CLASS_NAME.split(".")[2].toLowerCase();if(!this.extract[b])return null;this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));return("collection"==b?"GEOMETRYCOLLECTION":b.toUpperCase())+"("+this.extract[b].apply(this,[a])+")"},extract:{point:function(a){return a.x+" "+a.y},multipoint:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.point.apply(this,[a.components[c]])+
")");return b.join(",")},linestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b.join(",")},multilinestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.linestring.apply(this,[a.components[c]])+")");return b.join(",")},polygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.linestring.apply(this,[a.components[c]])+")");return b.join(",")},multipolygon:function(a){for(var b=
[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.polygon.apply(this,[a.components[c]])+")");return b.join(",")},collection:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extractGeometry.apply(this,[a.components[c]]));return b.join(",")}},parse:{point:function(a){a=OpenLayers.String.trim(a).split(this.regExes.spaces);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(a[0],a[1]))},multipoint:function(a){for(var b=OpenLayers.String.trim(a).split(","),
c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.point.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPoint(c))},linestring:function(a){a=OpenLayers.String.trim(a).split(",");for(var b=[],c=0,d=a.length;c<d;++c)b.push(this.parse.point.apply(this,[a[c]]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(b))},multilinestring:function(a){for(var b=OpenLayers.String.trim(a).split(this.regExes.parenComma),
c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.linestring.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiLineString(c))},polygon:function(a){var b;a=OpenLayers.String.trim(a).split(this.regExes.parenComma);for(var c=[],d=0,e=a.length;d<e;++d)b=a[d].replace(this.regExes.trimParens,"$1"),b=this.parse.linestring.apply(this,[b]).geometry,b=new OpenLayers.Geometry.LinearRing(b.components),c.push(b);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon(c))},
multipolygon:function(a){for(var b=OpenLayers.String.trim(a).split(this.regExes.doubleParenComma),c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.polygon.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPolygon(c))},geometrycollection:function(a){a=a.replace(/,\s*([A-Za-z])/g,"|$1");a=OpenLayers.String.trim(a).split("|");for(var b=[],c=0,d=a.length;c<d;++c)b.push(OpenLayers.Format.WKT.prototype.read.apply(this,[a[c]]));
return b}},CLASS_NAME:"OpenLayers.Format.WKT"});OpenLayers.WPSProcess=OpenLayers.Class({client:null,server:null,identifier:null,description:null,localWPS:"http://geoserver/wps",formats:null,chained:0,executeCallbacks:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.executeCallbacks=[];this.formats={"application/wkt":new OpenLayers.Format.WKT,"application/json":new OpenLayers.Format.GeoJSON}},describe:function(a){a=a||{};if(!this.description)this.client.describeProcess(this.server,this.identifier,function(b){this.description||this.parseDescription(b);
a.callback&&a.callback.call(a.scope,this.description)},this);else if(a.callback){var b=this.description;window.setTimeout(function(){a.callback.call(a.scope,b)},0)}},configure:function(a){this.describe({callback:function(){var b=this.description,c=a.inputs,d,e,f;e=0;for(f=b.dataInputs.length;e<f;++e)d=b.dataInputs[e],this.setInputData(d,c[d.identifier]);a.callback&&a.callback.call(a.scope)},scope:this});return this},execute:function(a){this.configure({inputs:a.inputs,callback:function(){var b=this,
c=this.getOutputIndex(b.description.processOutputs,a.output);b.setResponseForm({outputIndex:c});(function e(){OpenLayers.Util.removeItem(b.executeCallbacks,e);0!==b.chained?b.executeCallbacks.push(e):OpenLayers.Request.POST({url:b.client.servers[b.server].url,data:(new OpenLayers.Format.WPSExecute).write(b.description),success:function(e){var g=b.findMimeType(b.description.processOutputs[c].complexOutput.supported.formats);e=b.formats[g].read(e.responseText);e instanceof OpenLayers.Feature.Vector&&
(e=[e]);a.success&&(g={},g[a.output||"result"]=e,a.success.call(a.scope,g))},scope:b})})()},scope:this})},output:function(a){return new OpenLayers.WPSProcess.ChainLink({process:this,output:a})},parseDescription:function(a){a=this.client.servers[this.server];this.description=(new OpenLayers.Format.WPSDescribeProcess).read(a.processDescription[this.identifier]).processDescriptions[this.identifier]},setInputData:function(a,b){delete a.data;delete a.reference;if(b instanceof OpenLayers.WPSProcess.ChainLink)++this.chained,
a.reference={method:"POST",href:b.process.server===this.server?this.localWPS:this.client.servers[b.process.server].url},b.process.describe({callback:function(){--this.chained;this.chainProcess(a,b)},scope:this});else{a.data={};var c=a.complexData;c?(c=this.findMimeType(c.supported.formats),a.data.complexData={mimeType:c,value:this.formats[c].write(this.toFeatures(b))}):a.data.literalData={value:b}}},setResponseForm:function(a){a=a||{};var b=this.description.processOutputs[a.outputIndex||0];this.description.responseForm=
{rawDataOutput:{identifier:b.identifier,mimeType:this.findMimeType(b.complexOutput.supported.formats,a.supportedFormats)}}},getOutputIndex:function(a,b){var c;if(b)for(var d=a.length-1;0<=d;--d){if(a[d].identifier===b){c=d;break}}else c=0;return c},chainProcess:function(a,b){var c=this.getOutputIndex(b.process.description.processOutputs,b.output);a.reference.mimeType=this.findMimeType(a.complexData.supported.formats,b.process.description.processOutputs[c].complexOutput.supported.formats);var d={};
d[a.reference.mimeType]=!0;b.process.setResponseForm({outputIndex:c,supportedFormats:d});for(a.reference.body=b.process.description;0<this.executeCallbacks.length;)this.executeCallbacks[0]()},toFeatures:function(a){var b=OpenLayers.Util.isArray(a);b||(a=[a]);for(var c=Array(a.length),d,e=0,f=a.length;e<f;++e)d=a[e],c[e]=d instanceof OpenLayers.Feature.Vector?d:new OpenLayers.Feature.Vector(d);return b?c:c[0]},findMimeType:function(a,b){b=b||this.formats;for(var c in a)if(c in b)return c},CLASS_NAME:"OpenLayers.WPSProcess"});
OpenLayers.WPSProcess.ChainLink=OpenLayers.Class({process:null,output:null,initialize:function(a){OpenLayers.Util.extend(this,a)},CLASS_NAME:"OpenLayers.WPSProcess.ChainLink"});OpenLayers.WPSClient=OpenLayers.Class({servers:null,version:"1.0.0",lazy:!1,events:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this);this.servers={};for(var b in a.servers)this.servers[b]="string"==typeof a.servers[b]?{url:a.servers[b],version:this.version,processDescription:{}}:a.servers[b]},execute:function(a){this.getProcess(a.server,a.process).execute({inputs:a.inputs,success:a.success,scope:a.scope})},getProcess:function(a,b){var c=new OpenLayers.WPSProcess({client:this,
server:a,identifier:b});this.lazy||c.describe();return c},describeProcess:function(a,b,c,d){var e=this.servers[a];e.processDescription[b]?window.setTimeout(function(){c.call(d,e.processDescription[b])},0):b in e.processDescription?this.events.register("describeprocess",this,function g(a){a.identifier===b&&(this.events.unregister("describeprocess",this,g),c.call(d,a.raw))}):(e.processDescription[b]=null,OpenLayers.Request.GET({url:e.url,params:{SERVICE:"WPS",VERSION:e.version,REQUEST:"DescribeProcess",
IDENTIFIER:b},success:function(a){e.processDescription[b]=a.responseText;this.events.triggerEvent("describeprocess",{identifier:b,raw:a.responseText})},scope:this}))},destroy:function(){this.events.destroy();this.servers=this.events=null},CLASS_NAME:"OpenLayers.WPSClient"});OpenLayers.Format.CSWGetRecords.v2_0_2=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{csw:"http://www.opengis.net/cat/csw/2.0.2",dc:"http://purl.org/dc/elements/1.1/",dct:"http://purl.org/dc/terms/",gmd:"http://www.isotc211.org/2005/gmd",geonet:"http://www.fao.org/geonetwork",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"csw",version:"2.0.2",schemaLocation:"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd",
requestId:null,resultType:null,outputFormat:null,outputSchema:null,startPosition:null,maxRecords:null,DistributedSearch:null,ResponseHandler:null,Query:null,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},
readers:{csw:{GetRecordsResponse:function(a,b){b.records=[];this.readChildNodes(a,b);var c=this.getAttributeNS(a,"","version");""!=c&&(b.version=c)},RequestId:function(a,b){b.RequestId=this.getChildValue(a)},SearchStatus:function(a,b){b.SearchStatus={};var c=this.getAttributeNS(a,"","timestamp");""!=c&&(b.SearchStatus.timestamp=c)},SearchResults:function(a,b){this.readChildNodes(a,b);for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]="numberOfRecordsMatched"==c[e].name||"numberOfRecordsReturned"==
c[e].name||"nextRecord"==c[e].name?parseInt(c[e].nodeValue):c[e].nodeValue;b.SearchResults=d},SummaryRecord:function(a,b){var c={type:"SummaryRecord"};this.readChildNodes(a,c);b.records.push(c)},BriefRecord:function(a,b){var c={type:"BriefRecord"};this.readChildNodes(a,c);b.records.push(c)},DCMIRecord:function(a,b){var c={type:"DCMIRecord"};this.readChildNodes(a,c);b.records.push(c)},Record:function(a,b){var c={type:"Record"};this.readChildNodes(a,c);b.records.push(c)},"*":function(a,b){var c=a.localName||
a.nodeName.split(":").pop();b[c]=this.getChildValue(a)}},geonet:{info:function(a,b){var c={};this.readChildNodes(a,c);b.gninfo=c}},dc:{"*":function(a,b){var c=a.localName||a.nodeName.split(":").pop();OpenLayers.Util.isArray(b[c])||(b[c]=[]);for(var d={},e=a.attributes,f=0,g=e.length;f<g;++f)d[e[f].name]=e[f].nodeValue;d.value=this.getChildValue(a);""!=d.value&&b[c].push(d)}},dct:{"*":function(a,b){var c=a.localName||a.nodeName.split(":").pop();OpenLayers.Util.isArray(b[c])||(b[c]=[]);b[c].push(this.getChildValue(a))}},
ows:OpenLayers.Util.applyDefaults({BoundingBox:function(a,b){b.bounds&&(b.BoundingBox=[{crs:b.projection,value:[b.bounds.left,b.bounds.bottom,b.bounds.right,b.bounds.top]}],delete b.projection,delete b.bounds);OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows.BoundingBox.apply(this,arguments)}},OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows)},write:function(a){a=this.writeNode("csw:GetRecords",a);a.setAttribute("xmlns:gmd",this.namespaces.gmd);return OpenLayers.Format.XML.prototype.write.apply(this,
[a])},writers:{csw:{GetRecords:function(a){a||(a={});var b=this.createElementNSPlus("csw:GetRecords",{attributes:{service:"CSW",version:this.version,requestId:a.requestId||this.requestId,resultType:a.resultType||this.resultType,outputFormat:a.outputFormat||this.outputFormat,outputSchema:a.outputSchema||this.outputSchema,startPosition:a.startPosition||this.startPosition,maxRecords:a.maxRecords||this.maxRecords}});(a.DistributedSearch||this.DistributedSearch)&&this.writeNode("csw:DistributedSearch",
a.DistributedSearch||this.DistributedSearch,b);var c=a.ResponseHandler||this.ResponseHandler;if(OpenLayers.Util.isArray(c)&&0<c.length)for(var d=0,e=c.length;d<e;d++)this.writeNode("csw:ResponseHandler",c[d],b);this.writeNode("Query",a.Query||this.Query,b);return b},DistributedSearch:function(a){return this.createElementNSPlus("csw:DistributedSearch",{attributes:{hopCount:a.hopCount}})},ResponseHandler:function(a){return this.createElementNSPlus("csw:ResponseHandler",{value:a.value})},Query:function(a){a||
(a={});var b=this.createElementNSPlus("csw:Query",{attributes:{typeNames:a.typeNames||"csw:Record"}}),c=a.ElementName;if(OpenLayers.Util.isArray(c)&&0<c.length)for(var d=0,e=c.length;d<e;d++)this.writeNode("csw:ElementName",c[d],b);else this.writeNode("csw:ElementSetName",a.ElementSetName||{value:"summary"},b);a.Constraint&&this.writeNode("csw:Constraint",a.Constraint,b);a.SortBy&&this.writeNode("ogc:SortBy",a.SortBy,b);return b},ElementName:function(a){return this.createElementNSPlus("csw:ElementName",
{value:a.value})},ElementSetName:function(a){return this.createElementNSPlus("csw:ElementSetName",{attributes:{typeNames:a.typeNames},value:a.value})},Constraint:function(a){var b=this.createElementNSPlus("csw:Constraint",{attributes:{version:a.version}});if(a.Filter){var c=new OpenLayers.Format.Filter({version:a.version});b.appendChild(c.write(a.Filter))}else a.CqlText&&(a=this.createElementNSPlus("CqlText",{value:a.CqlText.value}),b.appendChild(a));return b}},ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc},
CLASS_NAME:"OpenLayers.Format.CSWGetRecords.v2_0_2"});/*
 Apache 2 

 Contains portions of Rico <http://openrico.org/>

 Copyright 2005 Sabre Airline Solutions  

 Licensed under the Apache License, Version 2.0 (the "License"); you
 may not use this file except in compliance with the License. You
 may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0  

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 implied. See the License for the specific language governing
 permissions and limitations under the License. 
*/
OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,initialize:function(a,b,c){this.bounds=a;this.div=OpenLayers.Util.createDiv();this.div.style.overflow="hidden";this.events=new OpenLayers.Events(this,this.div);this.setBorder(b,c)},destroy:function(){this.div=this.bounds=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments)},setBorder:function(a,b){a||(a="red");b||(b=2);this.div.style.border=b+"px solid "+a},draw:function(a,b){OpenLayers.Util.modifyDOMElement(this.div,
null,a,b);return this.div},onScreen:function(){var a=!1;this.map&&(a=this.map.getExtent().containsBounds(this.bounds,!0,!0));return a},display:function(a){this.div.style.display=a?"":"none"},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Format.Text=OpenLayers.Class(OpenLayers.Format,{defaultStyle:null,extractStyles:!0,initialize:function(a){a=a||{};!1!==a.extractStyles&&(a.defaultStyle={externalGraphic:OpenLayers.Util.getImageLocation("marker.png"),graphicWidth:21,graphicHeight:25,graphicXOffset:-10.5,graphicYOffset:-12.5});OpenLayers.Format.prototype.initialize.apply(this,[a])},read:function(a){a=a.split("\n");for(var b,c=[],d=0;d<a.length-1;d++){var e=a[d].replace(/^\s*/,"").replace(/\s*$/,"");if("#"!=e.charAt(0))if(b){for(var e=
e.split("\t"),f=new OpenLayers.Geometry.Point(0,0),g={},h=this.defaultStyle?OpenLayers.Util.applyDefaults({},this.defaultStyle):null,k=!1,l=0;l<e.length;l++)if(e[l])if("point"==b[l])k=e[l].split(","),f.y=parseFloat(k[0]),f.x=parseFloat(k[1]),k=!0;else if("lat"==b[l])f.y=parseFloat(e[l]),k=!0;else if("lon"==b[l])f.x=parseFloat(e[l]),k=!0;else if("title"==b[l])g.title=e[l];else if("image"==b[l]||"icon"==b[l]&&h)h.externalGraphic=e[l];else if("iconSize"==b[l]&&h){var m=e[l].split(",");h.graphicWidth=
parseFloat(m[0]);h.graphicHeight=parseFloat(m[1])}else"iconOffset"==b[l]&&h?(m=e[l].split(","),h.graphicXOffset=parseFloat(m[0]),h.graphicYOffset=parseFloat(m[1])):"description"==b[l]?g.description=e[l]:"overflow"==b[l]?g.overflow=e[l]:g[b[l]]=e[l];k&&(this.internalProjection&&this.externalProjection&&f.transform(this.externalProjection,this.internalProjection),e=new OpenLayers.Feature.Vector(f,g,h),c.push(e))}else b=e.split("\t")}return c},CLASS_NAME:"OpenLayers.Format.Text"});OpenLayers.Layer.Text=OpenLayers.Class(OpenLayers.Layer.Markers,{location:null,features:null,formatOptions:null,selectedFeature:null,initialize:function(a,b){OpenLayers.Layer.Markers.prototype.initialize.apply(this,arguments);this.features=[]},destroy:function(){OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);this.clearFeatures();this.features=null},loadText:function(){this.loaded||null==this.location||(this.events.triggerEvent("loadstart"),OpenLayers.Request.GET({url:this.location,
success:this.parseData,failure:function(a){this.events.triggerEvent("loadend")},scope:this}),this.loaded=!0)},moveTo:function(a,b,c){OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);this.visibility&&!this.loaded&&this.loadText()},parseData:function(a){a=a.responseText;var b={};OpenLayers.Util.extend(b,this.formatOptions);this.map&&!this.projection.equals(this.map.getProjectionObject())&&(b.externalProjection=this.projection,b.internalProjection=this.map.getProjectionObject());a=(new OpenLayers.Format.Text(b)).read(a);
for(var b=0,c=a.length;b<c;b++){var d={},e=a[b],f,g,h;f=new OpenLayers.LonLat(e.geometry.x,e.geometry.y);e.style.graphicWidth&&e.style.graphicHeight&&(g=new OpenLayers.Size(e.style.graphicWidth,e.style.graphicHeight));void 0!==e.style.graphicXOffset&&void 0!==e.style.graphicYOffset&&(h=new OpenLayers.Pixel(e.style.graphicXOffset,e.style.graphicYOffset));null!=e.style.externalGraphic?d.icon=new OpenLayers.Icon(e.style.externalGraphic,g,h):(d.icon=OpenLayers.Marker.defaultIcon(),null!=g&&d.icon.setSize(g));
null!=e.attributes.title&&null!=e.attributes.description&&(d.popupContentHTML="<h2>"+e.attributes.title+"</h2><p>"+e.attributes.description+"</p>");d.overflow=e.attributes.overflow||"auto";d=new OpenLayers.Feature(this,f,d);this.features.push(d);f=d.createMarker();null!=e.attributes.title&&null!=e.attributes.description&&f.events.register("click",d,this.markerClick);this.addMarker(f)}this.events.triggerEvent("loadend")},markerClick:function(a){var b=this==this.layer.selectedFeature;this.layer.selectedFeature=
b?null:this;for(var c=0,d=this.layer.map.popups.length;c<d;c++)this.layer.map.removePopup(this.layer.map.popups[c]);b||this.layer.map.addPopup(this.createPopup());OpenLayers.Event.stop(a)},clearFeatures:function(){if(null!=this.features)for(;0<this.features.length;){var a=this.features[0];OpenLayers.Util.removeItem(this.features,a);a.destroy()}},CLASS_NAME:"OpenLayers.Layer.Text"});OpenLayers.Handler.RegularPolygon=OpenLayers.Class(OpenLayers.Handler.Drag,{sides:4,radius:null,snapAngle:null,snapToggle:"shiftKey",layerOptions:null,persist:!1,irregular:!1,citeCompliant:!1,angle:null,fixedRadius:!1,feature:null,layer:null,origin:null,initialize:function(a,b,c){c&&c.layerOptions&&c.layerOptions.styleMap||(this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{}));OpenLayers.Handler.Drag.prototype.initialize.apply(this,[a,b,c]);this.options=c?c:{}},setOptions:function(a){OpenLayers.Util.extend(this.options,
a);OpenLayers.Util.extend(this,a)},activate:function(){var a=!1;OpenLayers.Handler.Drag.prototype.activate.apply(this,arguments)&&(a=OpenLayers.Util.extend({displayInLayerSwitcher:!1,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions),this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a),this.map.addLayer(this.layer),a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Handler.Drag.prototype.deactivate.apply(this,arguments)&&(this.dragging&&this.cancel(),
null!=this.layer.map&&(this.layer.destroy(!1),this.feature&&this.feature.destroy()),this.feature=this.layer=null,a=!0);return a},down:function(a){this.fixedRadius=!!this.radius;a=this.layer.getLonLatFromViewPortPx(a.xy);this.origin=new OpenLayers.Geometry.Point(a.lon,a.lat);if(!this.fixedRadius||this.irregular)this.radius=this.map.getResolution();this.persist&&this.clear();this.feature=new OpenLayers.Feature.Vector;this.createGeometry();this.callback("create",[this.origin,this.feature]);this.layer.addFeatures([this.feature],
{silent:!0});this.layer.drawFeature(this.feature,this.style)},move:function(a){var b=this.layer.getLonLatFromViewPortPx(a.xy),b=new OpenLayers.Geometry.Point(b.lon,b.lat);this.irregular?(a=Math.sqrt(2)*Math.abs(b.y-this.origin.y)/2,this.radius=Math.max(this.map.getResolution()/2,a)):this.fixedRadius?this.origin=b:(this.calculateAngle(b,a),this.radius=Math.max(this.map.getResolution()/2,b.distanceTo(this.origin)));this.modifyGeometry();if(this.irregular){a=b.x-this.origin.x;var b=b.y-this.origin.y,
c;c=0==b?a/(this.radius*Math.sqrt(2)):a/b;this.feature.geometry.resize(1,this.origin,c);this.feature.geometry.move(a/2,b/2)}this.layer.drawFeature(this.feature,this.style)},up:function(a){this.finalize();this.start==this.last&&this.callback("done",[a.xy])},out:function(a){this.finalize()},createGeometry:function(){this.angle=Math.PI*(1/this.sides-0.5);this.snapAngle&&(this.angle+=this.snapAngle*(Math.PI/180));this.feature.geometry=OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin,this.radius,
this.sides,this.snapAngle)},modifyGeometry:function(){var a,b,c=this.feature.geometry.components[0];c.components.length!=this.sides+1&&(this.createGeometry(),c=this.feature.geometry.components[0]);for(var d=0;d<this.sides;++d)b=c.components[d],a=this.angle+2*d*Math.PI/this.sides,b.x=this.origin.x+this.radius*Math.cos(a),b.y=this.origin.y+this.radius*Math.sin(a),b.clearBounds()},calculateAngle:function(a,b){var c=Math.atan2(a.y-this.origin.y,a.x-this.origin.x);if(this.snapAngle&&this.snapToggle&&!b[this.snapToggle]){var d=
Math.PI/180*this.snapAngle;this.angle=Math.round(c/d)*d}else this.angle=c},cancel:function(){this.callback("cancel",null);this.finalize()},finalize:function(){this.origin=null;this.radius=this.options.radius},clear:function(){this.layer&&(this.layer.renderer.clear(),this.layer.destroyFeatures())},callback:function(a,b){this.callbacks[a]&&this.callbacks[a].apply(this.control,[this.feature.geometry.clone()]);this.persist||"done"!=a&&"cancel"!=a||this.clear()},CLASS_NAME:"OpenLayers.Handler.RegularPolygon"});OpenLayers.Control.SLDSelect=OpenLayers.Class(OpenLayers.Control,{clearOnDeactivate:!1,layers:null,callbacks:null,selectionSymbolizer:{Polygon:{fillColor:"#FF0000",stroke:!1},Line:{strokeColor:"#FF0000",strokeWidth:2},Point:{graphicName:"square",fillColor:"#FF0000",pointRadius:5}},layerOptions:null,sketchStyle:null,wfsCache:{},layerCache:{},initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.callbacks=OpenLayers.Util.extend({done:this.select,click:this.select},this.callbacks);
this.handlerOptions=this.handlerOptions||{};this.layerOptions=OpenLayers.Util.applyDefaults(this.layerOptions,{displayInLayerSwitcher:!1,tileOptions:{maxGetUrlLength:2048}});this.sketchStyle&&(this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":this.sketchStyle})}));this.handler=new a(this,this.callbacks,this.handlerOptions)},destroy:function(){for(var a in this.layerCache)delete this.layerCache[a];for(a in this.wfsCache)delete this.wfsCache[a];
OpenLayers.Control.prototype.destroy.apply(this,arguments)},coupleLayerVisiblity:function(a){this.setVisibility(a.object.getVisibility())},createSelectionLayer:function(a){var b;if(this.layerCache[a.id])b=this.layerCache[a.id];else{b=new OpenLayers.Layer.WMS(a.name,a.url,a.params,OpenLayers.Util.applyDefaults(this.layerOptions,a.getOptions()));this.layerCache[a.id]=b;if(!1===this.layerOptions.displayInLayerSwitcher)a.events.on({visibilitychanged:this.coupleLayerVisiblity,scope:b});this.map.addLayer(b)}return b},
createSLD:function(a,b,c){for(var d={version:"1.0.0",namedLayers:{}},e=(""+a.params.LAYERS).split(","),f=0,g=e.length;f<g;f++){var h=e[f];d.namedLayers[h]={name:h,userStyles:[]};var k=this.selectionSymbolizer,l=c[f];0<=l.type.indexOf("Polygon")?k={Polygon:this.selectionSymbolizer.Polygon}:0<=l.type.indexOf("LineString")?k={Line:this.selectionSymbolizer.Line}:0<=l.type.indexOf("Point")&&(k={Point:this.selectionSymbolizer.Point});d.namedLayers[h].userStyles.push({name:"default",rules:[new OpenLayers.Rule({symbolizer:k,
filter:b[f],maxScaleDenominator:a.options.minScale})]})}return(new OpenLayers.Format.SLD({srsName:this.map.getProjection()})).write(d)},parseDescribeLayer:function(a){var b=new OpenLayers.Format.WMSDescribeLayer,c=a.responseXML;c&&c.documentElement||(c=a.responseText);a=b.read(c);for(var b=[],c=null,d=0,e=a.length;d<e;d++)"WFS"==a[d].owsType&&(b.push(a[d].typeName),c=a[d].owsURL);OpenLayers.Request.GET({url:c,params:{SERVICE:"WFS",TYPENAME:b.toString(),REQUEST:"DescribeFeatureType",VERSION:"1.0.0"},
callback:function(a){var b=new OpenLayers.Format.WFSDescribeFeatureType,c=a.responseXML;c&&c.documentElement||(c=a.responseText);a=b.read(c);this.control.wfsCache[this.layer.id]=a;this.control._queue&&this.control.applySelection()},scope:this})},getGeometryAttributes:function(a){var b=[];a=this.wfsCache[a.id];for(var c=0,d=a.featureTypes.length;c<d;c++)for(var e=a.featureTypes[c].properties,f=0,g=e.length;f<g;f++){var h=e[f],k=h.type;(0<=k.indexOf("LineString")||0<=k.indexOf("GeometryAssociationType")||
0<=k.indexOf("GeometryPropertyType")||0<=k.indexOf("Point")||0<=k.indexOf("Polygon"))&&b.push(h)}return b},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a)for(var b=0,c=this.layers.length;b<c;b++){var d=this.layers[b];d&&!this.wfsCache[d.id]&&OpenLayers.Request.GET({url:d.url,params:{SERVICE:"WMS",VERSION:d.params.VERSION,LAYERS:d.params.LAYERS,REQUEST:"DescribeLayer"},callback:this.parseDescribeLayer,scope:{layer:d,control:this}})}return a},deactivate:function(){var a=
OpenLayers.Control.prototype.deactivate.call(this);if(a)for(var b=0,c=this.layers.length;b<c;b++){var d=this.layers[b];if(d&&!0===this.clearOnDeactivate){var e=this.layerCache,f=e[d.id];f&&(d.events.un({visibilitychanged:this.coupleLayerVisiblity,scope:f}),f.destroy(),delete e[d.id])}}return a},setLayers:function(a){this.active?(this.deactivate(),this.layers=a,this.activate()):this.layers=a},createFilter:function(a,b){var c=null;this.handler instanceof OpenLayers.Handler.RegularPolygon?c=!0===this.handler.irregular?
new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,property:a.name,value:b.getBounds()}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Polygon?c=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Path?c=0<=a.type.indexOf("Point")?new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,
property:a.name,distance:0.01*this.map.getExtent().getWidth(),distanceUnits:this.map.getUnits(),value:b}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Click&&(c=0<=a.type.indexOf("Polygon")?new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,property:a.name,distance:0.01*this.map.getExtent().getWidth(),
distanceUnits:this.map.getUnits(),value:b}));return c},select:function(a){this._queue=function(){for(var b=0,c=this.layers.length;b<c;b++){for(var d=this.layers[b],e=this.getGeometryAttributes(d),f=[],g=0,h=e.length;g<h;g++){var k=e[g];if(null!==k){if(!(a instanceof OpenLayers.Geometry)){var l=this.map.getLonLatFromPixel(a.xy);a=new OpenLayers.Geometry.Point(l.lon,l.lat)}k=this.createFilter(k,a);null!==k&&f.push(k)}}g=this.createSelectionLayer(d);this.events.triggerEvent("selected",{layer:d,filters:f});
d=this.createSLD(d,f,e);g.mergeNewParams({SLD_BODY:d});delete this._queue}};this.applySelection()},applySelection:function(){for(var a=!0,b=0,c=this.layers.length;b<c;b++)if(!this.wfsCache[this.layers[b].id]){a=!1;break}a&&this._queue.call(this)},CLASS_NAME:"OpenLayers.Control.SLDSelect"});OpenLayers.Control.Scale=OpenLayers.Class(OpenLayers.Control,{element:null,geodesic:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.element=OpenLayers.Util.getElement(a)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.element||(this.element=document.createElement("div"),this.div.appendChild(this.element));this.map.events.register("moveend",this,this.updateScale);this.updateScale();return this.div},updateScale:function(){var a;
if(!0===this.geodesic){if(!this.map.getUnits())return;a=OpenLayers.INCHES_PER_UNIT;a=(this.map.getGeodesicPixelSize().w||1E-6)*a.km*OpenLayers.DOTS_PER_INCH}else a=this.map.getScale();a&&(a=9500<=a&&95E4>=a?Math.round(a/1E3)+"K":95E4<=a?Math.round(a/1E6)+"M":Math.round(a),this.element.innerHTML=OpenLayers.i18n("Scale = 1 : ${scaleDenom}",{scaleDenom:a}))},CLASS_NAME:"OpenLayers.Control.Scale"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,useHttpTile:!1,singleTile:!1,useOverlay:!1,useAsyncOverlay:!0,TILE_PARAMS:{operation:"GETTILEIMAGE",version:"1.2.0"},SINGLE_TILE_PARAMS:{operation:"GETMAPIMAGE",format:"PNG",locale:"en",clip:"1",version:"1.0.0"},OVERLAY_PARAMS:{operation:"GETDYNAMICMAPOVERLAYIMAGE",format:"PNG",locale:"en",clip:"1",version:"2.0.0"},FOLDER_PARAMS:{tileColumnsPerFolder:30,tileRowsPerFolder:30,format:"png",querystring:null},defaultSize:new OpenLayers.Size(300,
300),tileOriginCorner:"tl",initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);if(null==d||null==d.isBaseLayer)this.isBaseLayer="true"!=this.transparent&&!0!=this.transparent;d&&null!=d.useOverlay&&(this.useOverlay=d.useOverlay);this.singleTile?this.useOverlay?(OpenLayers.Util.applyDefaults(this.params,this.OVERLAY_PARAMS),this.useAsyncOverlay||(this.params.version="1.0.0")):OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS):(this.useHttpTile?
OpenLayers.Util.applyDefaults(this.params,this.FOLDER_PARAMS):OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS),this.setTileSize(this.defaultSize))},clone:function(a){null==a&&(a=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var b;b=a.getCenterLonLat();var c=this.map.getSize();this.singleTile?(a={setdisplaydpi:OpenLayers.DOTS_PER_INCH,setdisplayheight:c.h*this.ratio,setdisplaywidth:c.w*
this.ratio,setviewcenterx:b.lon,setviewcentery:b.lat,setviewscale:this.map.getScale()},this.useOverlay&&!this.useAsyncOverlay&&(b={},b=OpenLayers.Util.extend(b,a),b.operation="GETVISIBLEMAPEXTENT",b.version="1.0.0",b.session=this.params.session,b.mapName=this.params.mapName,b.format="text/xml",b=this.getFullRequestString(b),OpenLayers.Request.GET({url:b,async:!1})),b=this.getFullRequestString(a)):(c=this.map.getResolution(),b=Math.floor((a.left-this.maxExtent.left)/c),b=Math.round(b/this.tileSize.w),
a=Math.floor((this.maxExtent.top-a.top)/c),a=Math.round(a/this.tileSize.h),b=this.useHttpTile?this.getImageFilePath({tilecol:b,tilerow:a,scaleindex:this.resolutions.length-this.map.zoom-1}):this.getFullRequestString({tilecol:b,tilerow:a,scaleindex:this.resolutions.length-this.map.zoom-1}));return b},getFullRequestString:function(a,b){var c=null==b?this.url:b;"object"==typeof c&&(c=c[Math.floor(Math.random()*c.length)]);var d=c,e=OpenLayers.Util.extend({},this.params),e=OpenLayers.Util.extend(e,a),
f=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),g;for(g in e)g.toUpperCase()in f&&delete e[g];e=OpenLayers.Util.getParameterString(e);e=e.replace(/,/g,"+");""!=e&&(f=c.charAt(c.length-1),d="&"==f||"?"==f?d+e:-1==c.indexOf("?")?d+("?"+e):d+("&"+e));return d},getImageFilePath:function(a,b){var c=null==b?this.url:b;"object"==typeof c&&(c=c[Math.floor(Math.random()*c.length)]);var d="",e="";0>a.tilerow&&(d="-");d=0==a.tilerow?d+"0":d+Math.floor(Math.abs(a.tilerow/this.params.tileRowsPerFolder))*
this.params.tileRowsPerFolder;0>a.tilecol&&(e="-");e=0==a.tilecol?e+"0":e+Math.floor(Math.abs(a.tilecol/this.params.tileColumnsPerFolder))*this.params.tileColumnsPerFolder;d="/S"+Math.floor(a.scaleindex)+"/"+this.params.basemaplayergroupname+"/R"+d+"/C"+e+"/"+a.tilerow%this.params.tileRowsPerFolder+"_"+a.tilecol%this.params.tileColumnsPerFolder+"."+this.params.format;this.params.querystring&&(d+="?"+this.params.querystring);return c+d},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Control.Measure=OpenLayers.Class(OpenLayers.Control,{callbacks:null,displaySystem:"metric",geodesic:!1,displaySystemUnits:{geographic:["dd"],english:["mi","ft","in"],metric:["km","m"]},partialDelay:300,delayedTrigger:null,persist:!1,immediate:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);var c={done:this.measureComplete,point:this.measurePartial};this.immediate&&(c.modify=this.measureImmediate);this.callbacks=OpenLayers.Util.extend(c,this.callbacks);
this.handlerOptions=OpenLayers.Util.extend({persist:this.persist},this.handlerOptions);this.handler=new a(this,this.callbacks,this.handlerOptions)},deactivate:function(){this.cancelDelay();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},cancel:function(){this.cancelDelay();this.handler.cancel()},setImmediate:function(a){(this.immediate=a)?this.callbacks.modify=this.measureImmediate:delete this.callbacks.modify},updateHandler:function(a,b){var c=this.active;c&&this.deactivate();
this.handler=new a(this,this.callbacks,b);c&&this.activate()},measureComplete:function(a){this.cancelDelay();this.measure(a,"measure")},measurePartial:function(a,b){this.cancelDelay();b=b.clone();this.handler.freehandMode(this.handler.evt)?this.measure(b,"measurepartial"):this.delayedTrigger=window.setTimeout(OpenLayers.Function.bind(function(){this.delayedTrigger=null;this.measure(b,"measurepartial")},this),this.partialDelay)},measureImmediate:function(a,b,c){c&&!this.handler.freehandMode(this.handler.evt)&&
(this.cancelDelay(),this.measure(b.geometry,"measurepartial"))},cancelDelay:function(){null!==this.delayedTrigger&&(window.clearTimeout(this.delayedTrigger),this.delayedTrigger=null)},measure:function(a,b){var c,d;-1<a.CLASS_NAME.indexOf("LineString")?(c=this.getBestLength(a),d=1):(c=this.getBestArea(a),d=2);this.events.triggerEvent(b,{measure:c[0],units:c[1],order:d,geometry:a})},getBestArea:function(a){for(var b=this.displaySystemUnits[this.displaySystem],c,d,e=0,f=b.length;e<f&&!(c=b[e],d=this.getArea(a,
c),1<d);++e);return[d,c]},getArea:function(a,b){var c,d;this.geodesic?(c=a.getGeodesicArea(this.map.getProjectionObject()),d="m"):(c=a.getArea(),d=this.map.getUnits());var e=OpenLayers.INCHES_PER_UNIT[b];e&&(c*=Math.pow(OpenLayers.INCHES_PER_UNIT[d]/e,2));return c},getBestLength:function(a){for(var b=this.displaySystemUnits[this.displaySystem],c,d,e=0,f=b.length;e<f&&!(c=b[e],d=this.getLength(a,c),1<d);++e);return[d,c]},getLength:function(a,b){var c,d;this.geodesic?(c=a.getGeodesicLength(this.map.getProjectionObject()),
d="m"):(c=a.getLength(),d=this.map.getUnits());var e=OpenLayers.INCHES_PER_UNIT[b];e&&(c*=OpenLayers.INCHES_PER_UNIT[d]/e);return c},CLASS_NAME:"OpenLayers.Control.Measure"});OpenLayers.Format.WMC.v1_0_0=OpenLayers.Class(OpenLayers.Format.WMC.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd",initialize:function(a){OpenLayers.Format.WMC.v1.prototype.initialize.apply(this,[a])},read_wmc_SRS:function(a,b){var c=this.getChildValue(b);"object"!=typeof a.projections&&(a.projections={});for(var c=c.split(/ +/),d=0,e=c.length;d<e;d++)a.projections[c[d]]=!0},write_wmc_Layer:function(a){var b=OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this,
[a]);if(a.srs){var c=[],d;for(d in a.srs)c.push(d);b.appendChild(this.createElementDefaultNS("SRS",c.join(" ")))}b.appendChild(this.write_wmc_FormatList(a));b.appendChild(this.write_wmc_StyleList(a));a.dimensions&&b.appendChild(this.write_wmc_DimensionList(a));b.appendChild(this.write_wmc_LayerExtension(a))},CLASS_NAME:"OpenLayers.Format.WMC.v1_0_0"});OpenLayers.Popup.Anchored=OpenLayers.Class(OpenLayers.Popup,{relativePosition:null,keepInMap:!0,anchor:null,initialize:function(a,b,c,d,e,f,g){OpenLayers.Popup.prototype.initialize.apply(this,[a,b,c,d,f,g]);this.anchor=null!=e?e:{size:new OpenLayers.Size(0,0),offset:new OpenLayers.Pixel(0,0)}},destroy:function(){this.relativePosition=this.anchor=null;OpenLayers.Popup.prototype.destroy.apply(this,arguments)},show:function(){this.updatePosition();OpenLayers.Popup.prototype.show.apply(this,arguments)},
moveTo:function(a){var b=this.relativePosition;this.relativePosition=this.calculateRelativePosition(a);OpenLayers.Popup.prototype.moveTo.call(this,this.calculateNewPx(a));this.relativePosition!=b&&this.updateRelativePosition()},setSize:function(a){OpenLayers.Popup.prototype.setSize.apply(this,arguments);if(this.lonlat&&this.map){var b=this.map.getLayerPxFromLonLat(this.lonlat);this.moveTo(b)}},calculateRelativePosition:function(a){a=this.map.getLonLatFromLayerPx(a);a=this.map.getExtent().determineQuadrant(a);
return OpenLayers.Bounds.oppositeQuadrant(a)},updateRelativePosition:function(){},calculateNewPx:function(a){a=a.offset(this.anchor.offset);var b=this.size||this.contentSize,c="t"==this.relativePosition.charAt(0);a.y+=c?-b.h:this.anchor.size.h;c="l"==this.relativePosition.charAt(1);a.x+=c?-b.w:this.anchor.size.w;return a},CLASS_NAME:"OpenLayers.Popup.Anchored"});OpenLayers.Popup.Framed=OpenLayers.Class(OpenLayers.Popup.Anchored,{imageSrc:null,imageSize:null,isAlphaImage:!1,positionBlocks:null,blocks:null,fixedRelativePosition:!1,initialize:function(a,b,c,d,e,f,g){OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);this.fixedRelativePosition&&(this.updateRelativePosition(),this.calculateRelativePosition=function(a){return this.relativePosition});this.contentDiv.style.position="absolute";this.contentDiv.style.zIndex=1;f&&(this.closeDiv.style.zIndex=
1);this.groupDiv.style.position="absolute";this.groupDiv.style.top="0px";this.groupDiv.style.left="0px";this.groupDiv.style.height="100%";this.groupDiv.style.width="100%"},destroy:function(){this.isAlphaImage=this.imageSize=this.imageSrc=null;this.fixedRelativePosition=!1;this.positionBlocks=null;for(var a=0;a<this.blocks.length;a++){var b=this.blocks[a];b.image&&b.div.removeChild(b.image);b.image=null;b.div&&this.groupDiv.removeChild(b.div);b.div=null}this.blocks=null;OpenLayers.Popup.Anchored.prototype.destroy.apply(this,
arguments)},setBackgroundColor:function(a){},setBorder:function(){},setOpacity:function(a){},setSize:function(a){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.updateBlocks()},updateRelativePosition:function(){this.padding=this.positionBlocks[this.relativePosition].padding;if(this.closeDiv){var a=this.getContentDivPadding();this.closeDiv.style.right=a.right+this.padding.right+"px";this.closeDiv.style.top=a.top+this.padding.top+"px"}this.updateBlocks()},calculateNewPx:function(a){var b=
OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(this,arguments);return b=b.offset(this.positionBlocks[this.relativePosition].offset)},createBlocks:function(){this.blocks=[];var a=null,b;for(b in this.positionBlocks){a=b;break}a=this.positionBlocks[a];for(b=0;b<a.blocks.length;b++){var c={};this.blocks.push(c);c.div=OpenLayers.Util.createDiv(this.id+"_FrameDecorationDiv_"+b,null,null,null,"absolute",null,"hidden",null);c.image=(this.isAlphaImage?OpenLayers.Util.createAlphaImageDiv:OpenLayers.Util.createImage)(this.id+
"_FrameDecorationImg_"+b,null,this.imageSize,this.imageSrc,"absolute",null,null,null);c.div.appendChild(c.image);this.groupDiv.appendChild(c.div)}},updateBlocks:function(){this.blocks||this.createBlocks();if(this.size&&this.relativePosition){for(var a=this.positionBlocks[this.relativePosition],b=0;b<a.blocks.length;b++){var c=a.blocks[b],d=this.blocks[b],e=c.anchor.left,f=c.anchor.bottom,g=c.anchor.right,h=c.anchor.top,k=isNaN(c.size.w)?this.size.w-(g+e):c.size.w,l=isNaN(c.size.h)?this.size.h-(f+
h):c.size.h;d.div.style.width=(0>k?0:k)+"px";d.div.style.height=(0>l?0:l)+"px";d.div.style.left=null!=e?e+"px":"";d.div.style.bottom=null!=f?f+"px":"";d.div.style.right=null!=g?g+"px":"";d.div.style.top=null!=h?h+"px":"";d.image.style.left=c.position.x+"px";d.image.style.top=c.position.y+"px"}this.contentDiv.style.left=this.padding.left+"px";this.contentDiv.style.top=this.padding.top+"px"}},CLASS_NAME:"OpenLayers.Popup.Framed"});OpenLayers.Popup.FramedCloud=OpenLayers.Class(OpenLayers.Popup.Framed,{contentDisplayClass:"olFramedCloudPopupContent",autoSize:!0,panMapIfOutOfView:!0,imageSize:new OpenLayers.Size(1276,736),isAlphaImage:!1,fixedRelativePosition:!1,positionBlocks:{tl:{offset:new OpenLayers.Pixel(44,0),padding:new OpenLayers.Bounds(8,40,8,9),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,
50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,18),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-632)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(0,-688)}]},tr:{offset:new OpenLayers.Pixel(-45,0),padding:new OpenLayers.Bounds(8,40,8,9),blocks:[{size:new OpenLayers.Size("auto",
"auto"),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,19),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-631)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(0,
0,null,null),position:new OpenLayers.Pixel(-215,-687)}]},bl:{offset:new OpenLayers.Pixel(45,0),padding:new OpenLayers.Bounds(8,9,8,40),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,
21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(null,null,0,0),position:new OpenLayers.Pixel(-101,-674)}]},br:{offset:new OpenLayers.Pixel(-44,0),padding:new OpenLayers.Bounds(8,9,8,40),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,
0)},{size:new OpenLayers.Size("auto",21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(0,null,null,0),position:new OpenLayers.Pixel(-311,-674)}]}},minSize:new OpenLayers.Size(105,10),maxSize:new OpenLayers.Size(1200,660),initialize:function(a,b,c,d,e,f,g){this.imageSrc=OpenLayers.Util.getImageLocation("cloud-popup-relative.png");
OpenLayers.Popup.Framed.prototype.initialize.apply(this,arguments);this.contentDiv.className=this.contentDisplayClass},CLASS_NAME:"OpenLayers.Popup.FramedCloud"});OpenLayers.Tile.Image.IFrame={useIFrame:null,blankImageUrl:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7",draw:function(){if(OpenLayers.Tile.Image.prototype.shouldDraw.call(this)){var a=this.layer.getURL(this.bounds),b=this.useIFrame;this.useIFrame=null!==this.maxGetUrlLength&&!this.layer.async&&a.length>this.maxGetUrlLength;a=b&&!this.useIFrame;b=!b&&this.useIFrame;if(a||b)this.imgDiv&&this.imgDiv.parentNode===this.frame&&this.frame.removeChild(this.imgDiv),this.imgDiv=
null,a&&this.frame.removeChild(this.frame.firstChild)}return OpenLayers.Tile.Image.prototype.draw.apply(this,arguments)},getImage:function(){if(!0===this.useIFrame){if(!this.frame.childNodes.length){var a=document.createElement("div"),b=a.style;b.position="absolute";b.width="100%";b.height="100%";b.zIndex=1;b.backgroundImage="url("+this.blankImageUrl+")";this.frame.appendChild(a)}a=this.id+"_iFrame";9>parseFloat(navigator.appVersion.split("MSIE")[1])?(b=document.createElement('<iframe name="'+a+'">'),
b.style.backgroundColor="#FFFFFF",b.style.filter="chroma(color=#FFFFFF)"):(b=document.createElement("iframe"),b.style.backgroundColor="transparent",b.name=a);b.scrolling="no";b.marginWidth="0px";b.marginHeight="0px";b.frameBorder="0";b.style.position="absolute";b.style.width="100%";b.style.height="100%";1>this.layer.opacity&&OpenLayers.Util.modifyDOMElement(b,null,null,null,null,null,null,this.layer.opacity);this.frame.appendChild(b);return this.imgDiv=b}return OpenLayers.Tile.Image.prototype.getImage.apply(this,
arguments)},createRequestForm:function(){var a=document.createElement("form");a.method="POST";var b=this.layer.params._OLSALT,b=(b?b+"_":"")+this.bounds.toBBOX();a.action=OpenLayers.Util.urlAppend(this.layer.url,b);a.target=this.id+"_iFrame";this.layer.getImageSize();var b=OpenLayers.Util.getParameters(this.url),c,d;for(d in b)c=document.createElement("input"),c.type="hidden",c.name=d,c.value=b[d],a.appendChild(c);return a},setImgSrc:function(a){if(!0===this.useIFrame)if(a){var b=this.createRequestForm();
this.frame.appendChild(b);b.submit();this.frame.removeChild(b)}else this.imgDiv.parentNode===this.frame&&(this.frame.removeChild(this.imgDiv),this.imgDiv=null);else OpenLayers.Tile.Image.prototype.setImgSrc.apply(this,arguments)},onImageLoad:function(){OpenLayers.Tile.Image.prototype.onImageLoad.apply(this,arguments);!0===this.useIFrame&&(this.imgDiv.style.opacity=1,this.frame.style.opacity=this.layer.opacity)},createBackBuffer:function(){var a;!1===this.useIFrame&&(a=OpenLayers.Tile.Image.prototype.createBackBuffer.call(this));
return a}};OpenLayers.Format.SOSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.SOSCapabilities"});OpenLayers.Format.SOSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.SOSCapabilities,{namespaces:{ows:"http://www.opengis.net/ows/1.1",sos:"http://www.opengis.net/sos/1.0",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.options=a},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,
[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{gml:OpenLayers.Util.applyDefaults({name:function(a,b){b.name=this.getChildValue(a)},TimePeriod:function(a,b){b.timePeriod={};this.readChildNodes(a,b.timePeriod)},beginPosition:function(a,b){b.beginPosition=this.getChildValue(a)},endPosition:function(a,b){b.endPosition=this.getChildValue(a)}},OpenLayers.Format.GML.v3.prototype.readers.gml),sos:{Capabilities:function(a,b){this.readChildNodes(a,b)},Contents:function(a,
b){b.contents={};this.readChildNodes(a,b.contents)},ObservationOfferingList:function(a,b){b.offeringList={};this.readChildNodes(a,b.offeringList)},ObservationOffering:function(a,b){var c=this.getAttributeNS(a,this.namespaces.gml,"id");b[c]={procedures:[],observedProperties:[],featureOfInterestIds:[],responseFormats:[],resultModels:[],responseModes:[]};this.readChildNodes(a,b[c])},time:function(a,b){b.time={};this.readChildNodes(a,b.time)},procedure:function(a,b){b.procedures.push(this.getAttributeNS(a,
this.namespaces.xlink,"href"))},observedProperty:function(a,b){b.observedProperties.push(this.getAttributeNS(a,this.namespaces.xlink,"href"))},featureOfInterest:function(a,b){b.featureOfInterestIds.push(this.getAttributeNS(a,this.namespaces.xlink,"href"))},responseFormat:function(a,b){b.responseFormats.push(this.getChildValue(a))},resultModel:function(a,b){b.resultModels.push(this.getChildValue(a))},responseMode:function(a,b){b.responseModes.push(this.getChildValue(a))}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},
CLASS_NAME:"OpenLayers.Format.SOSCapabilities.v1_0_0"});OpenLayers.Handler.Pinch=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!1,pinching:!1,last:null,start:null,touchstart:function(a){var b=!0;this.pinching=!1;if(OpenLayers.Event.isMultiTouch(a))this.started=!0,this.last=this.start={distance:this.getDistance(a.touches),delta:0,scale:1},this.callback("start",[a,this.start]),b=!this.stopDown;else{if(this.started)return!1;this.started=!1;this.last=this.start=null}OpenLayers.Event.preventDefault(a);return b},touchmove:function(a){if(this.started&&
OpenLayers.Event.isMultiTouch(a)){this.pinching=!0;var b=this.getPinchData(a);this.callback("move",[a,b]);this.last=b;OpenLayers.Event.stop(a)}else if(this.started)return!1;return!0},touchend:function(a){return this.started&&!OpenLayers.Event.isMultiTouch(a)?(this.pinching=this.started=!1,this.callback("done",[a,this.start,this.last]),this.last=this.start=null,!1):!0},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.pinching=!1,a=!0);return a},deactivate:function(){var a=
!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.pinching=this.started=!1,this.last=this.start=null,a=!0);return a},getDistance:function(a){var b=a[0];a=a[1];return Math.sqrt(Math.pow(b.olClientX-a.olClientX,2)+Math.pow(b.olClientY-a.olClientY,2))},getPinchData:function(a){a=this.getDistance(a.touches);return{distance:a,delta:this.last.distance-a,scale:a/this.start.distance}},CLASS_NAME:"OpenLayers.Handler.Pinch"});OpenLayers.Control.NavToolbar=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);this.addControls([new OpenLayers.Control.Navigation,new OpenLayers.Control.ZoomBox])},draw:function(){var a=OpenLayers.Control.Panel.prototype.draw.apply(this,arguments);null===this.defaultControl&&(this.defaultControl=this.controls[0]);return a},CLASS_NAME:"OpenLayers.Control.NavToolbar"});OpenLayers.Strategy.Refresh=OpenLayers.Class(OpenLayers.Strategy,{force:!1,interval:0,timer:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);a&&(!0===this.layer.visibility&&this.start(),this.layer.events.on({visibilitychanged:this.reset,scope:this}));return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&(this.stop(),this.layer.events.un({visibilitychanged:this.reset,scope:this}));return a},reset:function(){!0===this.layer.visibility?
this.start():this.stop()},start:function(){this.interval&&("number"===typeof this.interval&&0<this.interval)&&(this.timer=window.setInterval(OpenLayers.Function.bind(this.refresh,this),this.interval))},refresh:function(){this.layer&&(this.layer.refresh&&"function"==typeof this.layer.refresh)&&this.layer.refresh({force:this.force})},stop:function(){null!==this.timer&&(window.clearInterval(this.timer),this.timer=null)},CLASS_NAME:"OpenLayers.Strategy.Refresh"});OpenLayers.Layer.ArcGIS93Rest=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{format:"png"},isBaseLayer:!0,initialize:function(a,b,c,d){var e=[];c=OpenLayers.Util.upperCaseObject(c);e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase()&&(null!=d&&d.isBaseLayer||(this.isBaseLayer=!1),"jpg"==this.params.FORMAT&&
(this.params.FORMAT=OpenLayers.Util.alphaHack()?"gif":"png"))},clone:function(a){null==a&&(a=new OpenLayers.Layer.ArcGIS93Rest(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){a=this.adjustBounds(a);var b=this.projection.getCode().split(":"),b=b[b.length-1],c=this.getImageSize();a={BBOX:a.toBBOX(),SIZE:c.w+","+c.h,F:"image",BBOXSR:b,IMAGESR:b};if(this.layerDefs){var b=[],d;for(d in this.layerDefs)this.layerDefs.hasOwnProperty(d)&&
this.layerDefs[d]&&(b.push(d),b.push(":"),b.push(this.layerDefs[d]),b.push(";"));0<b.length&&(a.LAYERDEFS=b.join(""))}return this.getFullRequestString(a)},setLayerFilter:function(a,b){this.layerDefs||(this.layerDefs={});b?this.layerDefs[a]=b:delete this.layerDefs[a]},clearLayerFilter:function(a){a?delete this.layerDefs[a]:delete this.layerDefs},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},CLASS_NAME:"OpenLayers.Layer.ArcGIS93Rest"});OpenLayers.Handler.Hover=OpenLayers.Class(OpenLayers.Handler,{delay:500,pixelTolerance:null,stopMove:!1,px:null,timerId:null,mousemove:function(a){this.passesTolerance(a.xy)&&(this.clearTimer(),this.callback("move",[a]),this.px=a.xy,a=OpenLayers.Util.extend({},a),this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,a),this.delay));return!this.stopMove},mouseout:function(a){OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv)&&(this.clearTimer(),this.callback("move",[a]));return!0},
passesTolerance:function(a){var b=!0;this.pixelTolerance&&this.px&&Math.sqrt(Math.pow(this.px.x-a.x,2)+Math.pow(this.px.y-a.y,2))<this.pixelTolerance&&(b=!1);return b},clearTimer:function(){null!=this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null)},delayedCall:function(a){this.callback("pause",[a])},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.clearTimer(),a=!0);return a},CLASS_NAME:"OpenLayers.Handler.Hover"});OpenLayers.Control.GetFeature=OpenLayers.Class(OpenLayers.Control,{protocol:null,multipleKey:null,toggleKey:null,modifiers:null,multiple:!1,click:!0,single:!0,clickout:!0,toggle:!1,clickTolerance:5,hover:!1,box:!1,maxFeatures:10,features:null,hoverFeature:null,handlers:null,hoverResponse:null,filterType:OpenLayers.Filter.Spatial.BBOX,initialize:function(a){a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.features={};this.handlers={};this.click&&(this.handlers.click=
new OpenLayers.Handler.Click(this,{click:this.selectClick},this.handlerOptions.click||{}));this.box&&(this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},OpenLayers.Util.extend(this.handlerOptions.box,{boxDivClassName:"olHandlerBoxSelectFeature"})));this.hover&&(this.handlers.hover=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.selectHover},OpenLayers.Util.extend(this.handlerOptions.hover,{delay:250,pixelTolerance:2})))},activate:function(){if(!this.active)for(var a in this.handlers)this.handlers[a].activate();
return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){if(this.active)for(var a in this.handlers)this.handlers[a].deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},selectClick:function(a){var b=this.pixelToBounds(a.xy);this.setModifiers(a);this.request(b,{single:this.single})},selectBox:function(a){var b;if(a instanceof OpenLayers.Bounds)b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom}),a=this.map.getLonLatFromPixel({x:a.right,
y:a.top}),b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat);else{if(this.click)return;b=this.pixelToBounds(a)}this.setModifiers(this.handlers.box.dragHandler.evt);this.request(b)},selectHover:function(a){a=this.pixelToBounds(a.xy);this.request(a,{single:!0,hover:!0})},cancelHover:function(){this.hoverResponse&&(this.protocol.abort(this.hoverResponse),this.hoverResponse=null,OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait"))},request:function(a,b){b=b||{};var c=new OpenLayers.Filter.Spatial({type:this.filterType,
value:a});OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");c=this.protocol.read({maxFeatures:!0==b.single?this.maxFeatures:void 0,filter:c,callback:function(c){c.success()&&(c.features.length?!0==b.single?this.selectBestFeature(c.features,a.getCenterLonLat(),b):this.select(c.features):b.hover?this.hoverSelect():(this.events.triggerEvent("clickout"),this.clickout&&this.unselectAll()));OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait")},scope:this});!0==b.hover&&(this.hoverResponse=
c)},selectBestFeature:function(a,b,c){c=c||{};if(a.length){b=new OpenLayers.Geometry.Point(b.lon,b.lat);for(var d,e,f,g=Number.MAX_VALUE,h=0;h<a.length&&!(d=a[h],d.geometry&&(f=b.distanceTo(d.geometry,{edge:!1}),f<g&&(g=f,e=d,0==g)));++h);!0==c.hover?this.hoverSelect(e):this.select(e||a)}},setModifiers:function(a){this.modifiers={multiple:this.multiple||this.multipleKey&&a[this.multipleKey],toggle:this.toggle||this.toggleKey&&a[this.toggleKey]}},select:function(a){this.modifiers.multiple||this.modifiers.toggle||
this.unselectAll();OpenLayers.Util.isArray(a)||(a=[a]);var b=this.events.triggerEvent("beforefeaturesselected",{features:a});if(!1!==b){for(var c=[],d,e=0,f=a.length;e<f;++e)d=a[e],this.features[d.fid||d.id]?this.modifiers.toggle&&this.unselect(this.features[d.fid||d.id]):(b=this.events.triggerEvent("beforefeatureselected",{feature:d}),!1!==b&&(this.features[d.fid||d.id]=d,c.push(d),this.events.triggerEvent("featureselected",{feature:d})));this.events.triggerEvent("featuresselected",{features:c})}},
hoverSelect:function(a){var b=a?a.fid||a.id:null,c=this.hoverFeature?this.hoverFeature.fid||this.hoverFeature.id:null;c&&c!=b&&(this.events.triggerEvent("outfeature",{feature:this.hoverFeature}),this.hoverFeature=null);b&&b!=c&&(this.events.triggerEvent("hoverfeature",{feature:a}),this.hoverFeature=a)},unselect:function(a){delete this.features[a.fid||a.id];this.events.triggerEvent("featureunselected",{feature:a})},unselectAll:function(){for(var a in this.features)this.unselect(this.features[a])},
setMap:function(a){for(var b in this.handlers)this.handlers[b].setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},pixelToBounds:function(a){var b=a.add(-this.clickTolerance/2,this.clickTolerance/2);a=a.add(this.clickTolerance/2,-this.clickTolerance/2);b=this.map.getLonLatFromPixel(b);a=this.map.getLonLatFromPixel(a);return new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat)},CLASS_NAME:"OpenLayers.Control.GetFeature"});OpenLayers.Format.QueryStringFilter=function(){function a(a){a=a.replace(/%/g,"\\%");a=a.replace(/\\\\\.(\*)?/g,function(a,b){return b?a:"\\\\_"});a=a.replace(/\\\\\.\*/g,"\\\\%");a=a.replace(/(\\)?\.(\*)?/g,function(a,b,c){return b||c?a:"_"});a=a.replace(/(\\)?\.\*/g,function(a,b){return b?a:"%"});a=a.replace(/\\\./g,".");return a=a.replace(/(\\)?\\\*/g,function(a,b){return b?a:"*"})}var b={};b[OpenLayers.Filter.Comparison.EQUAL_TO]="eq";b[OpenLayers.Filter.Comparison.NOT_EQUAL_TO]="ne";b[OpenLayers.Filter.Comparison.LESS_THAN]=
"lt";b[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO]="lte";b[OpenLayers.Filter.Comparison.GREATER_THAN]="gt";b[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO]="gte";b[OpenLayers.Filter.Comparison.LIKE]="ilike";return OpenLayers.Class(OpenLayers.Format,{wildcarded:!1,srsInBBOX:!1,write:function(c,d){d=d||{};var e=c.CLASS_NAME,e=e.substring(e.lastIndexOf(".")+1);switch(e){case "Spatial":switch(c.type){case OpenLayers.Filter.Spatial.BBOX:d.bbox=c.value.toArray();this.srsInBBOX&&c.projection&&
d.bbox.push(c.projection.getCode());break;case OpenLayers.Filter.Spatial.DWITHIN:d.tolerance=c.distance;case OpenLayers.Filter.Spatial.WITHIN:d.lon=c.value.x;d.lat=c.value.y;break;default:OpenLayers.Console.warn("Unknown spatial filter type "+c.type)}break;case "Comparison":e=b[c.type];if(void 0!==e){var f=c.value;c.type==OpenLayers.Filter.Comparison.LIKE&&(f=a(f),this.wildcarded&&(f="%"+f+"%"));d[c.property+"__"+e]=f;d.queryable=d.queryable||[];d.queryable.push(c.property)}else OpenLayers.Console.warn("Unknown comparison filter type "+
c.type);break;case "Logical":if(c.type===OpenLayers.Filter.Logical.AND)for(e=0,f=c.filters.length;e<f;e++)d=this.write(c.filters[e],d);else OpenLayers.Console.warn("Unsupported logical filter type "+c.type);break;default:OpenLayers.Console.warn("Unknown filter type "+e)}return d},CLASS_NAME:"OpenLayers.Format.QueryStringFilter"})}();OpenLayers.Control.MousePosition=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,element:null,prefix:"",separator:", ",suffix:"",numDigits:5,granularity:10,emptyString:null,lastXy:null,displayProjection:null,destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){return OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.map.events.register("mousemove",this,this.redraw),this.map.events.register("mouseout",this,this.reset),
this.redraw(),!0):!1},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,arguments)?(this.map.events.unregister("mousemove",this,this.redraw),this.map.events.unregister("mouseout",this,this.reset),this.element.innerHTML="",!0):!1},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.element||(this.div.left="",this.div.top="",this.element=this.div);return this.div},redraw:function(a){var b;if(null==a)this.reset();else if(null==this.lastXy||Math.abs(a.xy.x-
this.lastXy.x)>this.granularity||Math.abs(a.xy.y-this.lastXy.y)>this.granularity)this.lastXy=a.xy;else if(b=this.map.getLonLatFromPixel(a.xy))this.displayProjection&&b.transform(this.map.getProjectionObject(),this.displayProjection),this.lastXy=a.xy,a=this.formatOutput(b),a!=this.element.innerHTML&&(this.element.innerHTML=a)},reset:function(a){null!=this.emptyString&&(this.element.innerHTML=this.emptyString)},formatOutput:function(a){var b=parseInt(this.numDigits);return this.prefix+a.lon.toFixed(b)+
this.separator+a.lat.toFixed(b)+this.suffix},CLASS_NAME:"OpenLayers.Control.MousePosition"});OpenLayers.Control.Geolocate=OpenLayers.Class(OpenLayers.Control,{geolocation:null,available:"geolocation"in navigator,bind:!0,watch:!1,geolocationOptions:null,destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){this.available&&!this.geolocation&&(this.geolocation=navigator.geolocation);return this.geolocation?OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.watch?this.watchId=this.geolocation.watchPosition(OpenLayers.Function.bind(this.geolocate,
this),OpenLayers.Function.bind(this.failure,this),this.geolocationOptions):this.getCurrentLocation(),!0):!1:(this.events.triggerEvent("locationuncapable"),!1)},deactivate:function(){this.active&&null!==this.watchId&&this.geolocation.clearWatch(this.watchId);return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},geolocate:function(a){var b=(new OpenLayers.LonLat(a.coords.longitude,a.coords.latitude)).transform(new OpenLayers.Projection("EPSG:4326"),this.map.getProjectionObject());this.bind&&
this.map.setCenter(b);this.events.triggerEvent("locationupdated",{position:a,point:new OpenLayers.Geometry.Point(b.lon,b.lat)})},getCurrentLocation:function(){if(!this.active||this.watch)return!1;this.geolocation.getCurrentPosition(OpenLayers.Function.bind(this.geolocate,this),OpenLayers.Function.bind(this.failure,this),this.geolocationOptions);return!0},failure:function(a){this.events.triggerEvent("locationfailed",{error:a})},CLASS_NAME:"OpenLayers.Control.Geolocate"});OpenLayers.Tile.UTFGrid=OpenLayers.Class(OpenLayers.Tile,{url:null,utfgridResolution:2,json:null,format:null,destroy:function(){this.clear();OpenLayers.Tile.prototype.destroy.apply(this,arguments)},draw:function(){var a=OpenLayers.Tile.prototype.draw.apply(this,arguments);if(a)if(this.isLoading?(this.abortLoading(),this.events.triggerEvent("reload")):(this.isLoading=!0,this.events.triggerEvent("loadstart")),this.url=this.layer.getURL(this.bounds),this.layer.useJSONP){var b=new OpenLayers.Protocol.Script({url:this.url,
callback:function(a){this.isLoading=!1;this.events.triggerEvent("loadend");this.json=a.data},scope:this});b.read();this.request=b}else this.request=OpenLayers.Request.GET({url:this.url,callback:function(a){this.isLoading=!1;this.events.triggerEvent("loadend");200===a.status&&this.parseData(a.responseText)},scope:this});else this.unload();return a},abortLoading:function(){this.request&&(this.request.abort(),delete this.request);this.isLoading=!1},getFeatureInfo:function(a,b){var c=null;if(this.json){var d=
this.getFeatureId(a,b);null!==d&&(c={id:d,data:this.json.data[d]})}return c},getFeatureId:function(a,b){var c=null;if(this.json){var d=this.utfgridResolution,d=this.json.grid[Math.floor(b/d)].charCodeAt(Math.floor(a/d)),d=this.indexFromCharCode(d),e=this.json.keys;!isNaN(d)&&d in e&&(c=e[d])}return c},indexFromCharCode:function(a){93<=a&&a--;35<=a&&a--;return a-32},parseData:function(a){this.format||(this.format=new OpenLayers.Format.JSON);this.json=this.format.read(a)},clear:function(){this.json=
null},CLASS_NAME:"OpenLayers.Tile.UTFGrid"});OpenLayers.Protocol.HTTP=OpenLayers.Class(OpenLayers.Protocol,{url:null,headers:null,params:null,callback:null,scope:null,readWithPOST:!1,updateWithPOST:!1,deleteWithPOST:!1,wildcarded:!1,srsInBBOX:!1,initialize:function(a){a=a||{};this.params={};this.headers={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);if(!this.filterToParams&&OpenLayers.Format.QueryStringFilter){var b=new OpenLayers.Format.QueryStringFilter({wildcarded:this.wildcarded,srsInBBOX:this.srsInBBOX});this.filterToParams=
function(a,d){return b.write(a,d)}}},destroy:function(){this.headers=this.params=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=a||{};a.params=OpenLayers.Util.applyDefaults(a.params,this.options.params);a=OpenLayers.Util.applyDefaults(a,this.options);a.filter&&this.filterToParams&&(a.params=this.filterToParams(a.filter,a.params));var b=void 0!==a.readWithPOST?a.readWithPOST:this.readWithPOST,c=new OpenLayers.Protocol.Response({requestType:"read"});
b?(b=a.headers||{},b["Content-Type"]="application/x-www-form-urlencoded",c.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,c,a),data:OpenLayers.Util.getParameterString(a.params),headers:b})):c.priv=OpenLayers.Request.GET({url:a.url,callback:this.createCallback(this.handleRead,c,a),params:a.params,headers:a.headers});return c},handleRead:function(a,b){this.handleResponse(a,b)},create:function(a,b){b=OpenLayers.Util.applyDefaults(b,this.options);var c=new OpenLayers.Protocol.Response({reqFeatures:a,
requestType:"create"});c.priv=OpenLayers.Request.POST({url:b.url,callback:this.createCallback(this.handleCreate,c,b),headers:b.headers,data:this.format.write(a)});return c},handleCreate:function(a,b){this.handleResponse(a,b)},update:function(a,b){b=b||{};var c=b.url||a.url||this.options.url+"/"+a.fid;b=OpenLayers.Util.applyDefaults(b,this.options);var d=new OpenLayers.Protocol.Response({reqFeatures:a,requestType:"update"});d.priv=OpenLayers.Request[this.updateWithPOST?"POST":"PUT"]({url:c,callback:this.createCallback(this.handleUpdate,
d,b),headers:b.headers,data:this.format.write(a)});return d},handleUpdate:function(a,b){this.handleResponse(a,b)},"delete":function(a,b){b=b||{};var c=b.url||a.url||this.options.url+"/"+a.fid;b=OpenLayers.Util.applyDefaults(b,this.options);var d=new OpenLayers.Protocol.Response({reqFeatures:a,requestType:"delete"}),e=this.deleteWithPOST?"POST":"DELETE",c={url:c,callback:this.createCallback(this.handleDelete,d,b),headers:b.headers};this.deleteWithPOST&&(c.data=this.format.write(a));d.priv=OpenLayers.Request[e](c);
return d},handleDelete:function(a,b){this.handleResponse(a,b)},handleResponse:function(a,b){var c=a.priv;b.callback&&(200<=c.status&&300>c.status?("delete"!=a.requestType&&(a.features=this.parseFeatures(c)),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE,b.callback.call(b.scope,a))},parseFeatures:function(a){var b=a.responseXML;b&&b.documentElement||(b=a.responseText);return!b||0>=b.length?null:this.format.read(b)},commit:function(a,b){function c(a){for(var b=
a.features?a.features.length:0,c=Array(b),e=0;e<b;++e)c[e]=a.features[e].fid;r.insertIds=c;d.apply(this,[a])}function d(a){this.callUserCallback(a,b);q=q&&a.success();f++;f>=p&&b.callback&&(r.code=q?OpenLayers.Protocol.Response.SUCCESS:OpenLayers.Protocol.Response.FAILURE,b.callback.apply(b.scope,[r]))}b=OpenLayers.Util.applyDefaults(b,this.options);var e=[],f=0,g={};g[OpenLayers.State.INSERT]=[];g[OpenLayers.State.UPDATE]=[];g[OpenLayers.State.DELETE]=[];for(var h,k,l=[],m=0,n=a.length;m<n;++m)if(h=
a[m],k=g[h.state])k.push(h),l.push(h);var p=(0<g[OpenLayers.State.INSERT].length?1:0)+g[OpenLayers.State.UPDATE].length+g[OpenLayers.State.DELETE].length,q=!0,r=new OpenLayers.Protocol.Response({reqFeatures:l});h=g[OpenLayers.State.INSERT];0<h.length&&e.push(this.create(h,OpenLayers.Util.applyDefaults({callback:c,scope:this},b.create)));h=g[OpenLayers.State.UPDATE];for(m=h.length-1;0<=m;--m)e.push(this.update(h[m],OpenLayers.Util.applyDefaults({callback:d,scope:this},b.update)));h=g[OpenLayers.State.DELETE];
for(m=h.length-1;0<=m;--m)e.push(this["delete"](h[m],OpenLayers.Util.applyDefaults({callback:d,scope:this},b["delete"])));return e},abort:function(a){a&&a.priv.abort()},callUserCallback:function(a,b){var c=b[a.requestType];c&&c.callback&&c.callback.call(c.scope,a)},CLASS_NAME:"OpenLayers.Protocol.HTTP"});OpenLayers.Strategy.Cluster=OpenLayers.Class(OpenLayers.Strategy,{distance:20,threshold:null,features:null,clusters:null,clustering:!1,resolution:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a)this.layer.events.on({beforefeaturesadded:this.cacheFeatures,featuresremoved:this.clearCache,moveend:this.cluster,scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&(this.clearCache(),this.layer.events.un({beforefeaturesadded:this.cacheFeatures,
featuresremoved:this.clearCache,moveend:this.cluster,scope:this}));return a},cacheFeatures:function(a){var b=!0;this.clustering||(this.clearCache(),this.features=a.features,this.cluster(),b=!1);return b},clearCache:function(){this.clustering||(this.features=null)},cluster:function(a){if((!a||a.zoomChanged)&&this.features&&(a=this.layer.map.getResolution(),a!=this.resolution||!this.clustersExist())){this.resolution=a;a=[];for(var b,c,d,e=0;e<this.features.length;++e)if(b=this.features[e],b.geometry){c=
!1;for(var f=a.length-1;0<=f;--f)if(d=a[f],this.shouldCluster(d,b)){this.addToCluster(d,b);c=!0;break}c||a.push(this.createCluster(this.features[e]))}this.clustering=!0;this.layer.removeAllFeatures();this.clustering=!1;if(0<a.length){if(1<this.threshold)for(b=a.slice(),a=[],e=0,d=b.length;e<d;++e)c=b[e],c.attributes.count<this.threshold?Array.prototype.push.apply(a,c.cluster):a.push(c);this.clustering=!0;this.layer.addFeatures(a);this.clustering=!1}this.clusters=a}},clustersExist:function(){var a=
!1;if(this.clusters&&0<this.clusters.length&&this.clusters.length==this.layer.features.length)for(var a=!0,b=0;b<this.clusters.length;++b)if(this.clusters[b]!=this.layer.features[b]){a=!1;break}return a},shouldCluster:function(a,b){var c=a.geometry.getBounds().getCenterLonLat(),d=b.geometry.getBounds().getCenterLonLat();return Math.sqrt(Math.pow(c.lon-d.lon,2)+Math.pow(c.lat-d.lat,2))/this.resolution<=this.distance},addToCluster:function(a,b){a.cluster.push(b);a.attributes.count+=1},createCluster:function(a){var b=
a.geometry.getBounds().getCenterLonLat(),b=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(b.lon,b.lat),{count:1});b.cluster=[a];return b},CLASS_NAME:"OpenLayers.Strategy.Cluster"});OpenLayers.Strategy.Filter=OpenLayers.Class(OpenLayers.Strategy,{filter:null,cache:null,caching:!1,activate:function(){var a=OpenLayers.Strategy.prototype.activate.apply(this,arguments);a&&(this.cache=[],this.layer.events.on({beforefeaturesadded:this.handleAdd,beforefeaturesremoved:this.handleRemove,scope:this}));return a},deactivate:function(){this.cache=null;this.layer&&this.layer.events&&this.layer.events.un({beforefeaturesadded:this.handleAdd,beforefeaturesremoved:this.handleRemove,scope:this});
return OpenLayers.Strategy.prototype.deactivate.apply(this,arguments)},handleAdd:function(a){if(!this.caching&&this.filter){var b=a.features;a.features=[];for(var c,d=0,e=b.length;d<e;++d)c=b[d],this.filter.evaluate(c)?a.features.push(c):this.cache.push(c)}},handleRemove:function(a){this.caching||(this.cache=[])},setFilter:function(a){this.filter=a;a=this.cache;this.cache=[];this.handleAdd({features:this.layer.features});0<this.cache.length&&(this.caching=!0,this.layer.removeFeatures(this.cache.slice()),
this.caching=!1);0<a.length&&(a={features:a},this.handleAdd(a),0<a.features.length&&(this.caching=!0,this.layer.addFeatures(a.features),this.caching=!1))},CLASS_NAME:"OpenLayers.Strategy.Filter"});OpenLayers.Protocol.SOS=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.SOS.DEFAULTS);var b=OpenLayers.Protocol.SOS["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported SOS version: "+a.version;return new b(a)};OpenLayers.Protocol.SOS.DEFAULTS={version:"1.0.0"};OpenLayers.Format.WFSDescribeFeatureType=OpenLayers.Class(OpenLayers.Format.XML,{regExes:{trimSpace:/^\s*|\s*$/g},namespaces:{xsd:"http://www.w3.org/2001/XMLSchema"},readers:{xsd:{schema:function(a,b){var c=[],d={},e,f;this.readChildNodes(a,{complexTypes:c,customTypes:d});var g=a.attributes,h,k;e=0;for(f=g.length;e<f;++e)h=g[e],k=h.name,0===k.indexOf("xmlns")?this.setNamespace(k.split(":")[1]||"",h.value):b[k]=h.value;b.featureTypes=c;b.targetPrefix=this.namespaceAlias[b.targetNamespace];e=0;for(f=
c.length;e<f;++e)g=c[e],h=d[g.typeName],d[g.typeName]&&(g.typeName=h.name)},complexType:function(a,b){var c={typeName:a.getAttribute("name")};this.readChildNodes(a,c);b.complexTypes.push(c)},complexContent:function(a,b){this.readChildNodes(a,b)},extension:function(a,b){this.readChildNodes(a,b)},sequence:function(a,b){var c={elements:[]};this.readChildNodes(a,c);b.properties=c.elements},element:function(a,b){var c;if(b.elements){var d={};c=a.attributes;for(var e,f=0,g=c.length;f<g;++f)e=c[f],d[e.name]=
e.value;c=d.type;c||(c={},this.readChildNodes(a,c),d.restriction=c,d.type=c.base);d.localType=(c.base||c).split(":").pop();b.elements.push(d);this.readChildNodes(a,d)}b.complexTypes&&(c=a.getAttribute("type"),d=c.split(":").pop(),b.customTypes[d]={name:a.getAttribute("name"),type:c})},annotation:function(a,b){b.annotation={};this.readChildNodes(a,b.annotation)},appinfo:function(a,b){b.appinfo||(b.appinfo=[]);b.appinfo.push(this.getChildValue(a))},documentation:function(a,b){b.documentation||(b.documentation=
[]);var c=this.getChildValue(a);b.documentation.push({lang:a.getAttribute("xml:lang"),textContent:c.replace(this.regExes.trimSpace,"")})},simpleType:function(a,b){this.readChildNodes(a,b)},restriction:function(a,b){b.base=a.getAttribute("base");this.readRestriction(a,b)}}},readRestriction:function(a,b){for(var c=a.childNodes,d,e,f=0,g=c.length;f<g;++f)d=c[f],1==d.nodeType&&(e=d.nodeName.split(":").pop(),d=d.getAttribute("value"),b[e]?("string"==typeof b[e]&&(b[e]=[b[e]]),b[e].push(d)):b[e]=d)},read:function(a){"string"==
typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};if("ExceptionReport"===a.nodeName.split(":").pop()){var c=new OpenLayers.Format.OGCExceptionReport;b.error=c.read(a)}else this.readNode(a,b);return b},CLASS_NAME:"OpenLayers.Format.WFSDescribeFeatureType"});OpenLayers.Format.GeoRSS=OpenLayers.Class(OpenLayers.Format.XML,{rssns:"http://backend.userland.com/rss2",featureNS:"http://mapserver.gis.umn.edu/mapserver",georssns:"http://www.georss.org/georss",geons:"http://www.w3.org/2003/01/geo/wgs84_pos#",featureTitle:"Untitled",featureDescription:"No Description",gmlParser:null,xy:!1,createGeometryFromItem:function(a){var b=this.getElementsByTagNameNS(a,this.georssns,"point"),c=this.getElementsByTagNameNS(a,this.geons,"lat"),d=this.getElementsByTagNameNS(a,
this.geons,"long"),e=this.getElementsByTagNameNS(a,this.georssns,"line"),f=this.getElementsByTagNameNS(a,this.georssns,"polygon"),g=this.getElementsByTagNameNS(a,this.georssns,"where");a=this.getElementsByTagNameNS(a,this.georssns,"box");if(0<b.length||0<c.length&&0<d.length){0<b.length?(c=OpenLayers.String.trim(b[0].firstChild.nodeValue).split(/\s+/),2!=c.length&&(c=OpenLayers.String.trim(b[0].firstChild.nodeValue).split(/\s*,\s*/))):c=[parseFloat(c[0].firstChild.nodeValue),parseFloat(d[0].firstChild.nodeValue)];
var h=new OpenLayers.Geometry.Point(c[1],c[0])}else if(0<e.length){c=OpenLayers.String.trim(this.getChildValue(e[0])).split(/\s+/);d=[];e=0;for(f=c.length;e<f;e+=2)b=new OpenLayers.Geometry.Point(c[e+1],c[e]),d.push(b);h=new OpenLayers.Geometry.LineString(d)}else if(0<f.length){c=OpenLayers.String.trim(this.getChildValue(f[0])).split(/\s+/);d=[];e=0;for(f=c.length;e<f;e+=2)b=new OpenLayers.Geometry.Point(c[e+1],c[e]),d.push(b);h=new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(d)])}else 0<
g.length?(this.gmlParser||(this.gmlParser=new OpenLayers.Format.GML({xy:this.xy})),h=this.gmlParser.parseFeature(g[0]).geometry):0<a.length&&(c=OpenLayers.String.trim(a[0].firstChild.nodeValue).split(/\s+/),d=[],3<c.length&&(b=new OpenLayers.Geometry.Point(c[1],c[0]),d.push(b),b=new OpenLayers.Geometry.Point(c[1],c[2]),d.push(b),b=new OpenLayers.Geometry.Point(c[3],c[2]),d.push(b),b=new OpenLayers.Geometry.Point(c[3],c[0]),d.push(b),b=new OpenLayers.Geometry.Point(c[1],c[0]),d.push(b)),h=new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(d)]));
h&&(this.internalProjection&&this.externalProjection)&&h.transform(this.externalProjection,this.internalProjection);return h},createFeatureFromItem:function(a){var b=this.createGeometryFromItem(a),c=this._getChildValue(a,"*","title",this.featureTitle),d=this._getChildValue(a,"*","description",this._getChildValue(a,"*","content",this._getChildValue(a,"*","summary",this.featureDescription))),e=this._getChildValue(a,"*","link");if(!e)try{e=this.getElementsByTagNameNS(a,"*","link")[0].getAttribute("href")}catch(f){e=
null}a=this._getChildValue(a,"*","id",null);b=new OpenLayers.Feature.Vector(b,{title:c,description:d,link:e});b.fid=a;return b},_getChildValue:function(a,b,c,d){return(a=this.getElementsByTagNameNS(a,b,c))&&a[0]&&a[0].firstChild&&a[0].firstChild.nodeValue?this.getChildValue(a[0]):void 0==d?"":d},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=null,b=this.getElementsByTagNameNS(a,"*","item");0==b.length&&(b=this.getElementsByTagNameNS(a,"*","entry"));
a=b.length;for(var c=Array(a),d=0;d<a;d++)c[d]=this.createFeatureFromItem(b[d]);return c},write:function(a){var b;if(OpenLayers.Util.isArray(a)){b=this.createElementNS(this.rssns,"rss");for(var c=0,d=a.length;c<d;c++)b.appendChild(this.createFeatureXML(a[c]))}else b=this.createFeatureXML(a);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.rssns,"item"),d=this.createElementNS(this.rssns,"title");
d.appendChild(this.createTextNode(a.attributes.title?a.attributes.title:""));var e=this.createElementNS(this.rssns,"description");e.appendChild(this.createTextNode(a.attributes.description?a.attributes.description:""));c.appendChild(d);c.appendChild(e);a.attributes.link&&(d=this.createElementNS(this.rssns,"link"),d.appendChild(this.createTextNode(a.attributes.link)),c.appendChild(d));for(var f in a.attributes)"link"!=f&&("title"!=f&&"description"!=f)&&(d=this.createTextNode(a.attributes[f]),e=f,-1!=
f.search(":")&&(e=f.split(":")[1]),e=this.createElementNS(this.featureNS,"feature:"+e),e.appendChild(d),c.appendChild(e));c.appendChild(b);return c},buildGeometryNode:function(a){this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));var b;if("OpenLayers.Geometry.Polygon"==a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:polygon"),b.appendChild(this.buildCoordinatesNode(a.components[0]));else if("OpenLayers.Geometry.LineString"==
a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:line"),b.appendChild(this.buildCoordinatesNode(a));else if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:point"),b.appendChild(this.buildCoordinatesNode(a));else throw"Couldn't parse "+a.CLASS_NAME;return b},buildCoordinatesNode:function(a){var b=null;a.components&&(b=a.components);if(b){a=b.length;for(var c=Array(a),d=0;d<a;d++)c[d]=b[d].y+" "+b[d].x;b=c.join(" ")}else b=a.y+" "+a.x;return this.createTextNode(b)},
CLASS_NAME:"OpenLayers.Format.GeoRSS"});OpenLayers.Format.WPSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.WPSCapabilities"});OpenLayers.Format.WPSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows/1.1",wps:"http://www.opengis.net/wps/1.0.0",xlink:"http://www.w3.org/1999/xlink"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);
var b={};this.readNode(a,b);return b},readers:{wps:{Capabilities:function(a,b){this.readChildNodes(a,b)},ProcessOfferings:function(a,b){b.processOfferings={};this.readChildNodes(a,b.processOfferings)},Process:function(a,b){var c={processVersion:this.getAttributeNS(a,this.namespaces.wps,"processVersion")};this.readChildNodes(a,c);b[c.identifier]=c},Languages:function(a,b){b.languages=[];this.readChildNodes(a,b.languages)},Default:function(a,b){var c={isDefault:!0};this.readChildNodes(a,c);b.push(c)},
Supported:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WPSCapabilities.v1_0_0"});OpenLayers.Control.PinchZoom=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,pinchOrigin:null,currentCenter:null,autoActivate:!0,preserveCenter:!1,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.handler=new OpenLayers.Handler.Pinch(this,{start:this.pinchStart,move:this.pinchMove,done:this.pinchDone},this.handlerOptions)},pinchStart:function(a,b){var c=this.preserveCenter?this.map.getPixelFromLonLat(this.map.getCenter()):a.xy;this.currentCenter=
this.pinchOrigin=c},pinchMove:function(a,b){var c=b.scale,d=this.map.layerContainerOriginPx,e=this.pinchOrigin,f=this.preserveCenter?this.map.getPixelFromLonLat(this.map.getCenter()):a.xy,g=Math.round(d.x+f.x-e.x+(c-1)*(d.x-e.x)),d=Math.round(d.y+f.y-e.y+(c-1)*(d.y-e.y));this.map.applyTransform(g,d,c);this.currentCenter=f},pinchDone:function(a,b,c){this.map.applyTransform();a=this.map.getZoomForResolution(this.map.getResolution()/c.scale,!0);if(a!==this.map.getZoom()||!this.currentCenter.equals(this.pinchOrigin)){b=
this.map.getResolutionForZoom(a);c=this.map.getLonLatFromPixel(this.pinchOrigin);var d=this.currentCenter,e=this.map.getSize();c.lon+=b*(e.w/2-d.x);c.lat-=b*(e.h/2-d.y);this.map.div.clientWidth=this.map.div.clientWidth;this.map.setCenter(c,a)}},CLASS_NAME:"OpenLayers.Control.PinchZoom"});OpenLayers.Control.TouchNavigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,clickHandlerOptions:null,documentDrag:!1,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null;this.pinchZoom&&(this.pinchZoom.destroy(),delete this.pinchZoom);OpenLayers.Control.prototype.destroy.apply(this,
arguments)},activate:function(){return OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.dragPan.activate(),this.handlers.click.activate(),this.pinchZoom.activate(),!0):!1},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,arguments)?(this.dragPan.deactivate(),this.handlers.click.deactivate(),this.pinchZoom.deactivate(),!0):!1},draw:function(){var a={click:this.defaultClick,dblclick:this.defaultDblClick},b=OpenLayers.Util.extend({"double":!0,stopDouble:!0,
pixelTolerance:2},this.clickHandlerOptions);this.handlers.click=new OpenLayers.Handler.Click(this,a,b);this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,documentDrag:this.documentDrag},this.dragPanOptions));this.dragPan.draw();this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&&this.map.zoomOut()},defaultDblClick:function(a){this.map.zoomTo(this.map.zoom+
1,a.xy)},CLASS_NAME:"OpenLayers.Control.TouchNavigation"});OpenLayers.Console.warn("OpenLayers.Rico is deprecated");OpenLayers.Rico=OpenLayers.Rico||{};
OpenLayers.Rico.Color=OpenLayers.Class({initialize:function(a,b,c){this.rgb={r:a,g:b,b:c}},setRed:function(a){this.rgb.r=a},setGreen:function(a){this.rgb.g=a},setBlue:function(a){this.rgb.b=a},setHue:function(a){var b=this.asHSB();b.h=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setSaturation:function(a){var b=this.asHSB();b.s=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setBrightness:function(a){var b=this.asHSB();b.b=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},
darken:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.max(b.b-a,0))},brighten:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.min(b.b+a,1))},blend:function(a){this.rgb.r=Math.floor((this.rgb.r+a.rgb.r)/2);this.rgb.g=Math.floor((this.rgb.g+a.rgb.g)/2);this.rgb.b=Math.floor((this.rgb.b+a.rgb.b)/2)},isBright:function(){this.asHSB();return 0.5<this.asHSB().b},isDark:function(){return!this.isBright()},asRGB:function(){return"rgb("+
this.rgb.r+","+this.rgb.g+","+this.rgb.b+")"},asHex:function(){return"#"+this.rgb.r.toColorPart()+this.rgb.g.toColorPart()+this.rgb.b.toColorPart()},asHSB:function(){return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r,this.rgb.g,this.rgb.b)},toString:function(){return this.asHex()}});
OpenLayers.Rico.Color.createFromHex=function(a){if(4==a.length){var b=a;a="#";for(var c=1;4>c;c++)a+=b.charAt(c)+b.charAt(c)}0==a.indexOf("#")&&(a=a.substring(1));b=a.substring(0,2);c=a.substring(2,4);a=a.substring(4,6);return new OpenLayers.Rico.Color(parseInt(b,16),parseInt(c,16),parseInt(a,16))};
OpenLayers.Rico.Color.createColorFromBackground=function(a){var b=OpenLayers.Element.getStyle(OpenLayers.Util.getElement(a),"backgroundColor");return"transparent"==b&&a.parentNode?OpenLayers.Rico.Color.createColorFromBackground(a.parentNode):null==b?new OpenLayers.Rico.Color(255,255,255):0==b.indexOf("rgb(")?(a=b.substring(4,b.length-1).split(","),new OpenLayers.Rico.Color(parseInt(a[0]),parseInt(a[1]),parseInt(a[2]))):0==b.indexOf("#")?OpenLayers.Rico.Color.createFromHex(b):new OpenLayers.Rico.Color(255,
255,255)};
OpenLayers.Rico.Color.HSBtoRGB=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=parseInt(255*c+0.5);else{a=6*(a-Math.floor(a));var g=a-Math.floor(a),h=c*(1-b),k=c*(1-b*g);b=c*(1-b*(1-g));switch(parseInt(a)){case 0:d=255*c+0.5;e=255*b+0.5;f=255*h+0.5;break;case 1:d=255*k+0.5;e=255*c+0.5;f=255*h+0.5;break;case 2:d=255*h+0.5;e=255*c+0.5;f=255*b+0.5;break;case 3:d=255*h+0.5;e=255*k+0.5;f=255*c+0.5;break;case 4:d=255*b+0.5;e=255*h+0.5;f=255*c+0.5;break;case 5:d=255*c+0.5,e=255*h+0.5,f=255*k+0.5}}return{r:parseInt(d),g:parseInt(e),
b:parseInt(f)}};OpenLayers.Rico.Color.RGBtoHSB=function(a,b,c){var d,e=a>b?a:b;c>e&&(e=c);var f=a<b?a:b;c<f&&(f=c);d=0!=e?(e-f)/e:0;if(0==d)a=0;else{var g=(e-a)/(e-f),h=(e-b)/(e-f);c=(e-c)/(e-f);a=(a==e?c-h:b==e?2+g-c:4+h-g)/6;0>a&&(a+=1)}return{h:a,s:d,b:e/255}};OpenLayers.Style2=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:!1,rules:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a=0,b=this.rules.length;a<b;a++)this.rules[a].destroy();delete this.rules},clone:function(){var a=OpenLayers.Util.extend({},this);if(this.rules){a.rules=[];for(var b=0,c=this.rules.length;b<c;++b)a.rules.push(this.rules[b].clone())}return new OpenLayers.Style2(a)},
CLASS_NAME:"OpenLayers.Style2"});OpenLayers.Format.WFS=OpenLayers.Class(OpenLayers.Format.GML,{layer:null,wfsns:"http://www.opengis.net/wfs",ogcns:"http://www.opengis.net/ogc",initialize:function(a,b){OpenLayers.Format.GML.prototype.initialize.apply(this,[a]);this.layer=b;this.layer.featureNS&&(this.featureNS=this.layer.featureNS);this.layer.options.geometry_column&&(this.geometryName=this.layer.options.geometry_column);this.layer.options.typename&&(this.featureName=this.layer.options.typename)},write:function(a){var b=this.createElementNS(this.wfsns,
"wfs:Transaction");b.setAttribute("version","1.0.0");b.setAttribute("service","WFS");for(var c=0;c<a.length;c++)switch(a[c].state){case OpenLayers.State.INSERT:b.appendChild(this.insert(a[c]));break;case OpenLayers.State.UPDATE:b.appendChild(this.update(a[c]));break;case OpenLayers.State.DELETE:b.appendChild(this.remove(a[c]))}return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.featureNS,"feature:"+
this.geometryName);c.appendChild(b);b=this.createElementNS(this.featureNS,"feature:"+this.featureName);b.appendChild(c);for(var d in a.attributes){var c=this.createTextNode(a.attributes[d]),e=d;-1!=d.search(":")&&(e=d.split(":")[1]);e=this.createElementNS(this.featureNS,"feature:"+e);e.appendChild(c);b.appendChild(e)}return b},insert:function(a){var b=this.createElementNS(this.wfsns,"wfs:Insert");b.appendChild(this.createFeatureXML(a));return b},update:function(a){a.fid||OpenLayers.Console.userError(OpenLayers.i18n("noFID"));
var b=this.createElementNS(this.wfsns,"wfs:Update");b.setAttribute("typeName",this.featurePrefix+":"+this.featureName);b.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);var c=this.createElementNS(this.wfsns,"wfs:Property"),d=this.createElementNS(this.wfsns,"wfs:Name"),e=this.createTextNode(this.geometryName);d.appendChild(e);c.appendChild(d);d=this.createElementNS(this.wfsns,"wfs:Value");e=this.buildGeometryNode(a.geometry);a.layer&&e.setAttribute("srsName",a.layer.projection.getCode());
d.appendChild(e);c.appendChild(d);b.appendChild(c);for(var f in a.attributes)c=this.createElementNS(this.wfsns,"wfs:Property"),d=this.createElementNS(this.wfsns,"wfs:Name"),d.appendChild(this.createTextNode(f)),c.appendChild(d),d=this.createElementNS(this.wfsns,"wfs:Value"),d.appendChild(this.createTextNode(a.attributes[f])),c.appendChild(d),b.appendChild(c);c=this.createElementNS(this.ogcns,"ogc:Filter");f=this.createElementNS(this.ogcns,"ogc:FeatureId");f.setAttribute("fid",a.fid);c.appendChild(f);
b.appendChild(c);return b},remove:function(a){if(!a.fid)return OpenLayers.Console.userError(OpenLayers.i18n("noFID")),!1;var b=this.createElementNS(this.wfsns,"wfs:Delete");b.setAttribute("typeName",this.featurePrefix+":"+this.featureName);b.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);var c=this.createElementNS(this.ogcns,"ogc:Filter"),d=this.createElementNS(this.ogcns,"ogc:FeatureId");d.setAttribute("fid",a.fid);c.appendChild(d);b.appendChild(c);return b},destroy:function(){this.layer=
null},CLASS_NAME:"OpenLayers.Format.WFS"});OpenLayers.Format.SLD.v1_0_0_GeoServer=OpenLayers.Class(OpenLayers.Format.SLD.v1_0_0,{version:"1.0.0",profile:"GeoServer",readers:OpenLayers.Util.applyDefaults({sld:OpenLayers.Util.applyDefaults({Priority:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.priority=c)},VendorOption:function(a,b){b.vendorOptions||(b.vendorOptions={});b.vendorOptions[a.getAttribute("name")]=this.getChildValue(a)},TextSymbolizer:function(a,b){OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this,
arguments);var c=this.multipleSymbolizers?b.symbolizers[b.symbolizers.length-1]:b.symbolizer.Text;void 0===c.graphic&&(c.graphic=!1)}},OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld)},OpenLayers.Format.SLD.v1_0_0.prototype.readers),writers:OpenLayers.Util.applyDefaults({sld:OpenLayers.Util.applyDefaults({Priority:function(a){return this.writers.sld._OGCExpression.call(this,"sld:Priority",a)},VendorOption:function(a){return this.createElementNSPlus("sld:VendorOption",{attributes:{name:a.name},
value:a.value})},TextSymbolizer:function(a){var b=OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.TextSymbolizer.apply(this,arguments);!1!==a.graphic&&(a.externalGraphic||a.graphicName)&&this.writeNode("Graphic",a,b);"priority"in a&&this.writeNode("Priority",a.priority,b);return this.addVendorOptions(b,a)},PointSymbolizer:function(a){var b=OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.PointSymbolizer.apply(this,arguments);return this.addVendorOptions(b,a)},LineSymbolizer:function(a){var b=
OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.LineSymbolizer.apply(this,arguments);return this.addVendorOptions(b,a)},PolygonSymbolizer:function(a){var b=OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.PolygonSymbolizer.apply(this,arguments);return this.addVendorOptions(b,a)}},OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld)},OpenLayers.Format.SLD.v1_0_0.prototype.writers),addVendorOptions:function(a,b){if(b.vendorOptions)for(var c in b.vendorOptions)this.writeNode("VendorOption",{name:c,
value:b.vendorOptions[c]},a);return a},CLASS_NAME:"OpenLayers.Format.SLD.v1_0_0_GeoServer"});OpenLayers.Layer.Boxes=OpenLayers.Class(OpenLayers.Layer.Markers,{drawMarker:function(a){var b=this.map.getLayerPxFromLonLat({lon:a.bounds.left,lat:a.bounds.top}),c=this.map.getLayerPxFromLonLat({lon:a.bounds.right,lat:a.bounds.bottom});null==c||null==b?a.display(!1):(b=a.draw(b,{w:Math.max(1,c.x-b.x),h:Math.max(1,c.y-b.y)}),a.drawn||(this.div.appendChild(b),a.drawn=!0))},removeMarker:function(a){OpenLayers.Util.removeItem(this.markers,a);null!=a.div&&a.div.parentNode==this.div&&this.div.removeChild(a.div)},
CLASS_NAME:"OpenLayers.Layer.Boxes"});OpenLayers.Format.WFSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1,{readers:{wfs:OpenLayers.Util.applyDefaults({Service:function(a,b){b.service={};this.readChildNodes(a,b.service)},Fees:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.fees=c)},AccessConstraints:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.accessConstraints=c)},OnlineResource:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.onlineResource=
c)},Keywords:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.keywords=c.split(", "))},Capability:function(a,b){b.capability={};this.readChildNodes(a,b.capability)},Request:function(a,b){b.request={};this.readChildNodes(a,b.request)},GetFeature:function(a,b){b.getfeature={href:{},formats:[]};this.readChildNodes(a,b.getfeature)},ResultFormat:function(a,b){for(var c=a.childNodes,d,e=0;e<c.length;e++)d=c[e],1==d.nodeType&&b.formats.push(d.nodeName)},DCPType:function(a,b){this.readChildNodes(a,
b)},HTTP:function(a,b){this.readChildNodes(a,b.href)},Get:function(a,b){b.get=a.getAttribute("onlineResource")},Post:function(a,b){b.post=a.getAttribute("onlineResource")},SRS:function(a,b){var c=this.getChildValue(a);c&&(b.srs=c)}},OpenLayers.Format.WFSCapabilities.v1.prototype.readers.wfs)},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1_0_0"});OpenLayers.Format.WMSCapabilities.v1_3=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1,{readers:{wms:OpenLayers.Util.applyDefaults({WMS_Capabilities:function(a,b){this.readChildNodes(a,b)},LayerLimit:function(a,b){b.layerLimit=parseInt(this.getChildValue(a))},MaxWidth:function(a,b){b.maxWidth=parseInt(this.getChildValue(a))},MaxHeight:function(a,b){b.maxHeight=parseInt(this.getChildValue(a))},BoundingBox:function(a,b){var c=OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms.BoundingBox.apply(this,
[a,b]);c.srs=a.getAttribute("CRS");b.bbox[c.srs]=c},CRS:function(a,b){this.readers.wms.SRS.apply(this,[a,b])},EX_GeographicBoundingBox:function(a,b){b.llbbox=[];this.readChildNodes(a,b.llbbox)},westBoundLongitude:function(a,b){b[0]=this.getChildValue(a)},eastBoundLongitude:function(a,b){b[2]=this.getChildValue(a)},southBoundLatitude:function(a,b){b[1]=this.getChildValue(a)},northBoundLatitude:function(a,b){b[3]=this.getChildValue(a)},MinScaleDenominator:function(a,b){b.maxScale=parseFloat(this.getChildValue(a)).toPrecision(16)},
MaxScaleDenominator:function(a,b){b.minScale=parseFloat(this.getChildValue(a)).toPrecision(16)},Dimension:function(a,b){var c={name:a.getAttribute("name").toLowerCase(),units:a.getAttribute("units"),unitsymbol:a.getAttribute("unitSymbol"),nearestVal:"1"===a.getAttribute("nearestValue"),multipleVal:"1"===a.getAttribute("multipleValues"),"default":a.getAttribute("default")||"",current:"1"===a.getAttribute("current"),values:this.getChildValue(a).split(",")};b.dimensions[c.name]=c},Keyword:function(a,
b){var c={value:this.getChildValue(a),vocabulary:a.getAttribute("vocabulary")};b.keywords&&b.keywords.push(c)}},OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms),sld:{UserDefinedSymbolization:function(a,b){this.readers.wms.UserDefinedSymbolization.apply(this,[a,b]);b.userSymbols.inlineFeature=1==parseInt(a.getAttribute("InlineFeature"));b.userSymbols.remoteWCS=1==parseInt(a.getAttribute("RemoteWCS"))},DescribeLayer:function(a,b){this.readers.wms.DescribeLayer.apply(this,[a,b])},GetLegendGraphic:function(a,
b){this.readers.wms.GetLegendGraphic.apply(this,[a,b])}}},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_3"});OpenLayers.Layer.Zoomify=OpenLayers.Class(OpenLayers.Layer.Grid,{size:null,isBaseLayer:!0,standardTileSize:256,tileOriginCorner:"tl",numberOfTiers:0,tileCountUpToTier:null,tierSizeInTiles:null,tierImageSize:null,initialize:function(a,b,c,d){this.initializeZoomify(c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,c,{},d])},initializeZoomify:function(a){var b=a.clone();this.size=a.clone();a=new OpenLayers.Size(Math.ceil(b.w/this.standardTileSize),Math.ceil(b.h/this.standardTileSize));this.tierSizeInTiles=
[a];for(this.tierImageSize=[b];b.w>this.standardTileSize||b.h>this.standardTileSize;)b=new OpenLayers.Size(Math.floor(b.w/2),Math.floor(b.h/2)),a=new OpenLayers.Size(Math.ceil(b.w/this.standardTileSize),Math.ceil(b.h/this.standardTileSize)),this.tierSizeInTiles.push(a),this.tierImageSize.push(b);this.tierSizeInTiles.reverse();this.tierImageSize.reverse();this.numberOfTiers=this.tierSizeInTiles.length;b=[1];this.tileCountUpToTier=[0];for(a=1;a<this.numberOfTiers;a++)b.unshift(Math.pow(2,a)),this.tileCountUpToTier.push(this.tierSizeInTiles[a-
1].w*this.tierSizeInTiles[a-1].h+this.tileCountUpToTier[a-1]);this.serverResolutions||(this.serverResolutions=b)},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);this.tileCountUpToTier.length=0;this.tierSizeInTiles.length=0;this.tierImageSize.length=0},clone:function(a){null==a&&(a=new OpenLayers.Layer.Zoomify(this.name,this.url,this.size,this.options));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){a=this.adjustBounds(a);var b=
this.getServerResolution(),c=Math.round((a.left-this.tileOrigin.lon)/(b*this.tileSize.w));a=Math.round((this.tileOrigin.lat-a.top)/(b*this.tileSize.h));b=this.getZoomForResolution(b);c="TileGroup"+Math.floor((c+a*this.tierSizeInTiles[b].w+this.tileCountUpToTier[b])/256)+"/"+b+"-"+c+"-"+a+".jpg";b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(c,b));return b+c},getImageSize:function(){if(0<arguments.length){var a=this.adjustBounds(arguments[0]),b=this.getServerResolution(),c=Math.round((a.left-
this.tileOrigin.lon)/(b*this.tileSize.w)),a=Math.round((this.tileOrigin.lat-a.top)/(b*this.tileSize.h)),b=this.getZoomForResolution(b),d=this.standardTileSize,e=this.standardTileSize;c==this.tierSizeInTiles[b].w-1&&(d=this.tierImageSize[b].w%this.standardTileSize);a==this.tierSizeInTiles[b].h-1&&(e=this.tierImageSize[b].h%this.standardTileSize);return new OpenLayers.Size(d,e)}return this.tileSize},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,
this.map.maxExtent.top)},CLASS_NAME:"OpenLayers.Layer.Zoomify"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);if(null==d||null==d.isBaseLayer)this.isBaseLayer="true"!=this.params.transparent&&!0!=this.params.transparent},clone:function(a){null==a&&(a=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.getOptions()));
return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){a=this.adjustBounds(a);a=[a.left,a.bottom,a.right,a.top];var b=this.getImageSize();return this.getFullRequestString({mapext:a,imgext:a,map_size:[b.w,b.h],imgx:b.w/2,imgy:b.h/2,imgxy:[b.w,b.h]})},getFullRequestString:function(a,b){var c=null==b?this.url:b,d=OpenLayers.Util.extend({},this.params),d=OpenLayers.Util.extend(d,a),e=OpenLayers.Util.getParameterString(d);OpenLayers.Util.isArray(c)&&(c=this.selectUrl(e,c));
var e=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),f;for(f in d)f.toUpperCase()in e&&delete d[f];e=OpenLayers.Util.getParameterString(d);d=c;e=e.replace(/,/g,"+");""!=e&&(f=c.charAt(c.length-1),d="&"==f||"?"==f?d+e:-1==c.indexOf("?")?d+("?"+e):d+("&"+e));return d},CLASS_NAME:"OpenLayers.Layer.MapServer"});OpenLayers.Renderer.VML=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"urn:schemas-microsoft-com:vml",symbolCache:{},offset:null,initialize:function(a){if(this.supported()){if(!document.namespaces.olv){document.namespaces.add("olv",this.xmlns);for(var b=document.createStyleSheet(),c="shape rect oval fill stroke imagedata group textbox".split(" "),d=0,e=c.length;d<e;d++)b.addRule("olv\\:"+c[d],"behavior: url(#default#VML); position: absolute; display: inline-block;")}OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
arguments)}},supported:function(){return!!document.namespaces},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=a.left/d|0,d=a.top/d-this.size.h|0;b||!this.offset?(this.offset={x:e,y:d},d=e=0):(e-=this.offset.x,d-=this.offset.y);this.root.coordorigin=e-this.xOffset+" "+d;for(var e=[this.root,this.vectorRoot,this.textRoot],f=0,g=e.length;f<g;++f)d=e[f],d.coordsize=this.size.w+" "+this.size.h;this.root.style.flip="y";return c},
setSize:function(a){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);for(var b=[this.rendererRoot,this.root,this.vectorRoot,this.textRoot],c=this.size.w+"px",d=this.size.h+"px",e,f=0,g=b.length;f<g;++f)e=b[f],e.style.width=c,e.style.height=d},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"olv:rect":this.isComplexSymbol(b.graphicName)?"olv:shape":"olv:oval";break;case "OpenLayers.Geometry.Rectangle":c="olv:rect";break;case "OpenLayers.Geometry.LineString":case "OpenLayers.Geometry.LinearRing":case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c=
"olv:shape"}return c},setStyle:function(a,b,c,d){b=b||a._style;c=c||a._options;var e=b.fillColor,f=b.title||b.graphicTitle;f&&(a.title=f);if("OpenLayers.Geometry.Point"===a._geometryClass)if(b.externalGraphic){c.isFilled=!0;var e=b.graphicWidth||b.graphicHeight,f=b.graphicHeight||b.graphicWidth,e=e?e:2*b.pointRadius,f=f?f:2*b.pointRadius,g=this.getResolution(),h=void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*e),k=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*f);a.style.left=((d.x-this.featureDx)/
g-this.offset.x+h|0)+"px";a.style.top=(d.y/g-this.offset.y-(k+f)|0)+"px";a.style.width=e+"px";a.style.height=f+"px";a.style.flip="y";e="none";c.isStroked=!1}else this.isComplexSymbol(b.graphicName)?(f=this.importSymbol(b.graphicName),a.path=f.path,a.coordorigin=f.left+","+f.bottom,f=f.size,a.coordsize=f+","+f,this.drawCircle(a,d,b.pointRadius),a.style.flip="y"):this.drawCircle(a,d,b.pointRadius);c.isFilled?a.fillcolor=e:a.filled="false";d=a.getElementsByTagName("fill");d=0==d.length?null:d[0];c.isFilled?
(d||(d=this.createNode("olv:fill",a.id+"_fill")),d.opacity=b.fillOpacity,"OpenLayers.Geometry.Point"===a._geometryClass&&b.externalGraphic&&(b.graphicOpacity&&(d.opacity=b.graphicOpacity),d.src=b.externalGraphic,d.type="frame",b.graphicWidth&&b.graphicHeight||(d.aspect="atmost")),d.parentNode!=a&&a.appendChild(d)):d&&a.removeChild(d);e=b.rotation;if(void 0!==e||void 0!==a._rotation)a._rotation=e,b.externalGraphic?(this.graphicRotate(a,h,k,b),d.opacity=0):"OpenLayers.Geometry.Point"===a._geometryClass&&
(a.style.rotation=e||0);h=a.getElementsByTagName("stroke");h=0==h.length?null:h[0];c.isStroked?(h||(h=this.createNode("olv:stroke",a.id+"_stroke"),a.appendChild(h)),h.on=!0,h.color=b.strokeColor,h.weight=b.strokeWidth+"px",h.opacity=b.strokeOpacity,h.endcap="butt"==b.strokeLinecap?"flat":b.strokeLinecap||"round",b.strokeDashstyle&&(h.dashstyle=this.dashStyle(b))):(a.stroked=!1,h&&(h.on=!1));"inherit"!=b.cursor&&null!=b.cursor&&(a.style.cursor=b.cursor);return a},graphicRotate:function(a,b,c,d){d=
d||a._style;var e=d.rotation||0,f,g;if(d.graphicWidth&&d.graphicHeight){g=Math.max(d.graphicWidth,d.graphicHeight);f=d.graphicWidth/d.graphicHeight;var h=Math.round(d.graphicWidth||g*f),k=Math.round(d.graphicHeight||g);a.style.width=h+"px";a.style.height=k+"px";var l=document.getElementById(a.id+"_image");l||(l=this.createNode("olv:imagedata",a.id+"_image"),a.appendChild(l));l.style.width=h+"px";l.style.height=k+"px";l.src=d.externalGraphic;l.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='', sizingMethod='scale')";
l=e*Math.PI/180;e=Math.sin(l);l=Math.cos(l);e="progid:DXImageTransform.Microsoft.Matrix(M11="+l+",M12="+-e+",M21="+e+",M22="+l+",SizingMethod='auto expand')\n";(l=d.graphicOpacity||d.fillOpacity)&&1!=l&&(e+="progid:DXImageTransform.Microsoft.BasicImage(opacity="+l+")\n");a.style.filter=e;e=new OpenLayers.Geometry.Point(-b,-c);h=(new OpenLayers.Bounds(0,0,h,k)).toGeometry();h.rotate(d.rotation,e);h=h.getBounds();a.style.left=Math.round(parseInt(a.style.left)+h.left)+"px";a.style.top=Math.round(parseInt(a.style.top)-
h.bottom)+"px"}else{var m=new Image;m.onreadystatechange=OpenLayers.Function.bind(function(){if("complete"==m.readyState||"interactive"==m.readyState)f=m.width/m.height,g=Math.max(2*d.pointRadius,d.graphicWidth||0,d.graphicHeight||0),b*=f,d.graphicWidth=g*f,d.graphicHeight=g,this.graphicRotate(a,b,c,d)},this);m.src=d.externalGraphic}},postDraw:function(a){a.style.visibility="visible";var b=a._style.fillColor,c=a._style.strokeColor;"none"==b&&a.fillcolor!=b&&(a.fillcolor=b);"none"==c&&a.strokecolor!=
c&&(a.strokecolor=c)},setNodeDimension:function(a,b){var c=b.getBounds();if(c){var d=this.getResolution(),c=new OpenLayers.Bounds((c.left-this.featureDx)/d-this.offset.x|0,c.bottom/d-this.offset.y|0,(c.right-this.featureDx)/d-this.offset.x|0,c.top/d-this.offset.y|0);a.style.left=c.left+"px";a.style.top=c.top+"px";a.style.width=c.getWidth()+"px";a.style.height=c.getHeight()+"px";a.coordorigin=c.left+" "+c.top;a.coordsize=c.getWidth()+" "+c.getHeight()}},dashStyle:function(a){a=a.strokeDashstyle;switch(a){case "solid":case "dot":case "dash":case "dashdot":case "longdash":case "longdashdot":return a;
default:return a=a.split(/[ ,]/),2==a.length?1*a[0]>=2*a[1]?"longdash":1==a[0]||1==a[1]?"dot":"dash":4==a.length?1*a[0]>=2*a[1]?"longdashdot":"dashdot":"solid"}},createNode:function(a,b){var c=document.createElement(a);b&&(c.id=b);c.unselectable="on";c.onselectstart=OpenLayers.Function.False;return c},nodeTypeCompare:function(a,b){var c=b,d=c.indexOf(":");-1!=d&&(c=c.substr(d+1));var e=a.nodeName,d=e.indexOf(":");-1!=d&&(e=e.substr(d+1));return c==e},createRenderRoot:function(){return this.nodeFactory(this.container.id+
"_vmlRoot","div")},createRoot:function(a){return this.nodeFactory(this.container.id+a,"olv:group")},drawPoint:function(a,b){return this.drawCircle(a,b,1)},drawCircle:function(a,b,c){if(!isNaN(b.x)&&!isNaN(b.y)){var d=this.getResolution();a.style.left=((b.x-this.featureDx)/d-this.offset.x|0)-c+"px";a.style.top=(b.y/d-this.offset.y|0)-c+"px";b=2*c;a.style.width=b+"px";a.style.height=b+"px";return a}return!1},drawLineString:function(a,b){return this.drawLine(a,b,!1)},drawLinearRing:function(a,b){return this.drawLine(a,
b,!0)},drawLine:function(a,b,c){this.setNodeDimension(a,b);for(var d=this.getResolution(),e=b.components.length,f=Array(e),g,h,k=0;k<e;k++)g=b.components[k],h=(g.x-this.featureDx)/d-this.offset.x|0,g=g.y/d-this.offset.y|0,f[k]=" "+h+","+g+" l ";b=c?" x e":" e";a.path="m"+f.join("")+b;return a},drawPolygon:function(a,b){this.setNodeDimension(a,b);var c=this.getResolution(),d=[],e,f,g,h,k,l,m,n,p,q;e=0;for(f=b.components.length;e<f;e++){d.push("m");g=b.components[e].components;h=0===e;l=k=null;m=0;
for(n=g.length;m<n;m++)p=g[m],q=(p.x-this.featureDx)/c-this.offset.x|0,p=p.y/c-this.offset.y|0,q=" "+q+","+p,d.push(q),0==m&&d.push(" l"),h||(k?k!=q&&(l?l!=q&&(h=!0):l=q):k=q);d.push(h?" x ":" ")}d.push("e");a.path=d.join("");return a},drawRectangle:function(a,b){var c=this.getResolution();a.style.left=((b.x-this.featureDx)/c-this.offset.x|0)+"px";a.style.top=(b.y/c-this.offset.y|0)+"px";a.style.width=(b.width/c|0)+"px";a.style.height=(b.height/c|0)+"px";return a},drawText:function(a,b,c){var d=this.nodeFactory(a+
this.LABEL_ID_SUFFIX,"olv:rect"),e=this.nodeFactory(a+this.LABEL_ID_SUFFIX+"_textbox","olv:textbox"),f=this.getResolution();d.style.left=((c.x-this.featureDx)/f-this.offset.x|0)+"px";d.style.top=(c.y/f-this.offset.y|0)+"px";d.style.flip="y";e.innerText=b.label;"inherit"!=b.cursor&&null!=b.cursor&&(e.style.cursor=b.cursor);b.fontColor&&(e.style.color=b.fontColor);b.fontOpacity&&(e.style.filter="alpha(opacity="+100*b.fontOpacity+")");b.fontFamily&&(e.style.fontFamily=b.fontFamily);b.fontSize&&(e.style.fontSize=
b.fontSize);b.fontWeight&&(e.style.fontWeight=b.fontWeight);b.fontStyle&&(e.style.fontStyle=b.fontStyle);!0===b.labelSelect&&(d._featureId=a,e._featureId=a,e._geometry=c,e._geometryClass=c.CLASS_NAME);e.style.whiteSpace="nowrap";e.inset="1px,0px,0px,0px";d.parentNode||(d.appendChild(e),this.textRoot.appendChild(d));b=b.labelAlign||"cm";1==b.length&&(b+="m");a=e.clientWidth*OpenLayers.Renderer.VML.LABEL_SHIFT[b.substr(0,1)];e=e.clientHeight*OpenLayers.Renderer.VML.LABEL_SHIFT[b.substr(1,1)];d.style.left=
parseInt(d.style.left)-a-1+"px";d.style.top=parseInt(d.style.top)+e+"px"},moveRoot:function(a){var b=this.map.getLayer(a.container.id);b instanceof OpenLayers.Layer.Vector.RootContainer&&(b=this.map.getLayer(this.container.id));b&&b.renderer.clear();OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this,arguments);b&&b.redraw()},importSymbol:function(a){var b=this.container.id+"-"+a,c=this.symbolCache[b];if(c)return c;c=OpenLayers.Renderer.symbol[a];if(!c)throw Error(a+" is not a valid symbol name");
a=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);for(var d=["m"],e=0;e<c.length;e+=2){var f=c[e],g=c[e+1];a.left=Math.min(a.left,f);a.bottom=Math.min(a.bottom,g);a.right=Math.max(a.right,f);a.top=Math.max(a.top,g);d.push(f);d.push(g);0==e&&d.push("l")}d.push("x e");c=d.join(" ");d=(a.getWidth()-a.getHeight())/2;0<d?(a.bottom-=d,a.top+=d):(a.left+=d,a.right-=d);c={path:c,size:a.getWidth(),left:a.left,bottom:a.bottom};return this.symbolCache[b]=c},CLASS_NAME:"OpenLayers.Renderer.VML"});
OpenLayers.Renderer.VML.LABEL_SHIFT={l:0,c:0.5,r:1,t:0,m:0.5,b:1};OpenLayers.Control.CacheRead=OpenLayers.Class(OpenLayers.Control,{fetchEvent:"tileloadstart",layers:null,autoActivate:!0,setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);var b,c=this.layers||a.layers;for(b=c.length-1;0<=b;--b)this.addLayer({layer:c[b]});if(!this.layers)a.events.on({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this})},addLayer:function(a){a.layer.events.register(this.fetchEvent,this,this.fetch)},removeLayer:function(a){a.layer.events.unregister(this.fetchEvent,
this,this.fetch)},fetch:function(a){if(this.active&&window.localStorage&&a.tile instanceof OpenLayers.Tile.Image){var b=a.tile,c=b.url;!b.layer.crossOriginKeyword&&(OpenLayers.ProxyHost&&0===c.indexOf(OpenLayers.ProxyHost))&&(c=OpenLayers.Control.CacheWrite.urlMap[c]);if(c=window.localStorage.getItem("olCache_"+c))b.url=c,"tileerror"===a.type&&b.setImgSrc(c)}},destroy:function(){if(this.layers||this.map){var a,b=this.layers||this.map.layers;for(a=b.length-1;0<=a;--a)this.removeLayer({layer:b[a]})}this.map&&
this.map.events.un({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.CacheRead"});OpenLayers.Protocol.WFS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.0.0",CLASS_NAME:"OpenLayers.Protocol.WFS.v1_0_0"});OpenLayers.Format.WMSGetFeatureInfo=OpenLayers.Class(OpenLayers.Format.XML,{layerIdentifier:"_layer",featureIdentifier:"_feature",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},gmlFormat:null,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=a.documentElement;if(b){var c=this["read_"+b.nodeName];a=c?c.call(this,b):(new OpenLayers.Format.GML(this.options?this.options:{})).read(a)}return a},read_msGMLOutput:function(a){var b=
[];if(a=this.getSiblingNodesByTagCriteria(a,this.layerIdentifier))for(var c=0,d=a.length;c<d;++c){var e=a[c],f=e.nodeName;e.prefix&&(f=f.split(":")[1]);f=f.replace(this.layerIdentifier,"");if(e=this.getSiblingNodesByTagCriteria(e,this.featureIdentifier))for(var g=0;g<e.length;g++){var h=e[g],k=this.parseGeometry(h),h=this.parseAttributes(h),h=new OpenLayers.Feature.Vector(k.geometry,h,null);h.bounds=k.bounds;h.type=f;b.push(h)}}return b},read_FeatureInfoResponse:function(a){var b=[];a=this.getElementsByTagNameNS(a,
"*","FIELDS");for(var c=0,d=a.length;c<d;c++){var e=a[c],f={},g,h=e.attributes.length;if(0<h)for(g=0;g<h;g++){var k=e.attributes[g];f[k.nodeName]=k.nodeValue}else for(e=e.childNodes,g=0,h=e.length;g<h;++g)k=e[g],3!=k.nodeType&&(f[k.getAttribute("name")]=k.getAttribute("value"));b.push(new OpenLayers.Feature.Vector(null,f,null))}return b},getSiblingNodesByTagCriteria:function(a,b){var c=[],d,e,f,g;if(a&&a.hasChildNodes()){d=a.childNodes;f=d.length;for(var h=0;h<f;h++){for(g=d[h];g&&1!=g.nodeType;)g=
g.nextSibling,h++;e=g?g.nodeName:"";0<e.length&&-1<e.indexOf(b)?c.push(g):(e=this.getSiblingNodesByTagCriteria(g,b),0<e.length&&(0==c.length?c=e:c.push(e)))}}return c},parseAttributes:function(a){var b={};if(1==a.nodeType){a=a.childNodes;for(var c=a.length,d=0;d<c;++d){var e=a[d];if(1==e.nodeType){var f=e.childNodes,e=e.prefix?e.nodeName.split(":")[1]:e.nodeName;0==f.length?b[e]=null:1==f.length&&(f=f[0],3==f.nodeType||4==f.nodeType)&&(f=f.nodeValue.replace(this.regExes.trimSpace,""),b[e]=f)}}}return b},
parseGeometry:function(a){this.gmlFormat||(this.gmlFormat=new OpenLayers.Format.GML);a=this.gmlFormat.parseFeature(a);var b,c=null;a&&(b=a.geometry&&a.geometry.clone(),c=a.bounds&&a.bounds.clone(),a.destroy());return{geometry:b,bounds:c}},CLASS_NAME:"OpenLayers.Format.WMSGetFeatureInfo"});OpenLayers.Control.WMTSGetFeatureInfo=OpenLayers.Class(OpenLayers.Control,{hover:!1,requestEncoding:"KVP",drillDown:!1,maxFeatures:10,clickCallback:"click",layers:null,queryVisible:!0,infoFormat:"text/html",vendorParams:{},format:null,formatOptions:null,handler:null,hoverRequest:null,pending:0,initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.format||(this.format=new OpenLayers.Format.WMSGetFeatureInfo(a.formatOptions));
!0===this.drillDown&&(this.hover=!1);this.hover?this.handler=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.getInfoForHover},OpenLayers.Util.extend(this.handlerOptions.hover||{},{delay:250})):(a={},a[this.clickCallback]=this.getInfoForClick,this.handler=new OpenLayers.Handler.Click(this,a,this.handlerOptions.click||{}))},getInfoForClick:function(a){this.request(a.xy,{})},getInfoForHover:function(a){this.request(a.xy,{hover:!0})},cancelHover:function(){this.hoverRequest&&(--this.pending,
0>=this.pending&&(OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait"),this.pending=0),this.hoverRequest.abort(),this.hoverRequest=null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d=a.length-1;0<=d&&(c=a[d],!(c instanceof OpenLayers.Layer.WMTS)||(c.requestEncoding!==this.requestEncoding||this.queryVisible&&!c.getVisibility())||(b.push(c),this.drillDown&&!this.hover));--d);return b},buildRequestOptions:function(a,b){var c=this.map.getLonLatFromPixel(b),d=a.getURL(new OpenLayers.Bounds(c.lon,
c.lat,c.lon,c.lat)),d=OpenLayers.Util.getParameters(d),c=a.getTileInfo(c);OpenLayers.Util.extend(d,{service:"WMTS",version:a.version,request:"GetFeatureInfo",infoFormat:this.infoFormat,i:c.i,j:c.j});OpenLayers.Util.applyDefaults(d,this.vendorParams);return{url:OpenLayers.Util.isArray(a.url)?a.url[0]:a.url,params:OpenLayers.Util.upperCaseObject(d),callback:function(c){this.handleResponse(b,c,a)},scope:this}},request:function(a,b){b=b||{};var c=this.findLayers();if(0<c.length){for(var d,e,f=0,g=c.length;f<
g;f++)e=c[f],d=this.events.triggerEvent("beforegetfeatureinfo",{xy:a,layer:e}),!1!==d&&(++this.pending,d=this.buildRequestOptions(e,a),d=OpenLayers.Request.GET(d),!0===b.hover&&(this.hoverRequest=d));0<this.pending&&OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait")}},handleResponse:function(a,b,c){--this.pending;0>=this.pending&&(OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait"),this.pending=0);if(b.status&&(200>b.status||300<=b.status))this.events.triggerEvent("exception",
{xy:a,request:b,layer:c});else{var d=b.responseXML;d&&d.documentElement||(d=b.responseText);var e,f;try{e=this.format.read(d)}catch(g){f=!0,this.events.triggerEvent("exception",{xy:a,request:b,error:g,layer:c})}f||this.events.triggerEvent("getfeatureinfo",{text:b.responseText,features:e,request:b,xy:a,layer:c})}},CLASS_NAME:"OpenLayers.Control.WMTSGetFeatureInfo"});OpenLayers.Protocol.CSW.v2_0_2=OpenLayers.Class(OpenLayers.Protocol,{formatOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({},this.formatOptions)))},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,
this.options||{});var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.format.write(a.params||a);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),params:a.params,headers:a.headers,data:c});return b},handleRead:function(a,b){if(b.callback){var c=a.priv;200<=c.status&&300>c.status?(a.data=this.parseData(c),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE;b.callback.call(b.scope,a)}},parseData:function(a){var b=
a.responseXML;b&&b.documentElement||(b=a.responseText);return!b||0>=b.length?null:this.format.read(b)},CLASS_NAME:"OpenLayers.Protocol.CSW.v2_0_2"});OpenLayers.Format.WCSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1,{namespaces:{wcs:"http://www.opengis.net/wcs/1.1",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",ows:"http://www.opengis.net/ows/1.1"},errorProperty:"operationsMetadata",readers:{wcs:OpenLayers.Util.applyDefaults({Capabilities:function(a,b){this.readChildNodes(a,b)},Contents:function(a,b){b.contentMetadata=[];this.readChildNodes(a,b.contentMetadata)},CoverageSummary:function(a,
b){var c={};this.readChildNodes(a,c);b.push(c)},Identifier:function(a,b){b.identifier=this.getChildValue(a)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b["abstract"]=this.getChildValue(a)},SupportedCRS:function(a,b){var c=this.getChildValue(a);c&&(b.supportedCRS||(b.supportedCRS=[]),b.supportedCRS.push(c))},SupportedFormat:function(a,b){var c=this.getChildValue(a);c&&(b.supportedFormat||(b.supportedFormat=[]),b.supportedFormat.push(c))}},OpenLayers.Format.WCSCapabilities.v1.prototype.readers.wcs),
ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WCSCapabilities.v1_1_0"});OpenLayers.Control.Graticule=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,intervals:[45,30,20,10,5,2,1,0.5,0.2,0.1,0.05,0.01,0.005,0.002,0.001],displayInLayerSwitcher:!0,visible:!0,numPoints:50,targetSize:200,layerName:null,labelled:!0,labelFormat:"dm",lineSymbolizer:{strokeColor:"#333",strokeWidth:1,strokeOpacity:0.5},labelSymbolizer:{},gratLayer:null,initialize:function(a){a=a||{};a.layerName=a.layerName||OpenLayers.i18n("Graticule");OpenLayers.Control.prototype.initialize.apply(this,[a]);
this.labelSymbolizer.stroke=!1;this.labelSymbolizer.fill=!1;this.labelSymbolizer.label="${label}";this.labelSymbolizer.labelAlign="${labelAlign}";this.labelSymbolizer.labelXOffset="${xOffset}";this.labelSymbolizer.labelYOffset="${yOffset}"},destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments);this.gratLayer&&(this.gratLayer.destroy(),this.gratLayer=null)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.gratLayer){var a=new OpenLayers.Style({},
{rules:[new OpenLayers.Rule({symbolizer:{Point:this.labelSymbolizer,Line:this.lineSymbolizer}})]});this.gratLayer=new OpenLayers.Layer.Vector(this.layerName,{styleMap:new OpenLayers.StyleMap({"default":a}),visibility:this.visible,displayInLayerSwitcher:this.displayInLayerSwitcher})}return this.div},activate:function(){return OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.map.addLayer(this.gratLayer),this.map.events.register("moveend",this,this.update),this.update(),!0):!1},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,
arguments)?(this.map.events.unregister("moveend",this,this.update),this.map.removeLayer(this.gratLayer),!0):!1},update:function(){var a=this.map.getExtent();if(a){this.gratLayer.destroyFeatures();var b=new OpenLayers.Projection("EPSG:4326"),c=this.map.getProjectionObject(),d=this.map.getResolution();c.proj&&"longlat"==c.proj.projName&&(this.numPoints=1);var e=this.map.getCenter(),f=new OpenLayers.Pixel(e.lon,e.lat);OpenLayers.Projection.transform(f,c,b);for(var e=this.targetSize*d,e=e*e,g,d=0;d<this.intervals.length;++d){g=
this.intervals[d];var h=g/2,k=f.offset({x:-h,y:-h}),h=f.offset({x:h,y:h});OpenLayers.Projection.transform(k,b,c);OpenLayers.Projection.transform(h,b,c);if((k.x-h.x)*(k.x-h.x)+(k.y-h.y)*(k.y-h.y)<=e)break}f.x=Math.floor(f.x/g)*g;f.y=Math.floor(f.y/g)*g;var d=0,e=[f.clone()],h=f.clone(),l;do h=h.offset({x:0,y:g}),l=OpenLayers.Projection.transform(h.clone(),b,c),e.unshift(h);while(a.containsPixel(l)&&1E3>++d);h=f.clone();do h=h.offset({x:0,y:-g}),l=OpenLayers.Projection.transform(h.clone(),b,c),e.push(h);
while(a.containsPixel(l)&&1E3>++d);d=0;k=[f.clone()];h=f.clone();do h=h.offset({x:-g,y:0}),l=OpenLayers.Projection.transform(h.clone(),b,c),k.unshift(h);while(a.containsPixel(l)&&1E3>++d);h=f.clone();do h=h.offset({x:g,y:0}),l=OpenLayers.Projection.transform(h.clone(),b,c),k.push(h);while(a.containsPixel(l)&&1E3>++d);g=[];for(d=0;d<k.length;++d){l=k[d].x;for(var f=[],m=null,n=Math.min(e[0].y,90),h=Math.max(e[e.length-1].y,-90),p=(n-h)/this.numPoints,n=h,h=0;h<=this.numPoints;++h){var q=new OpenLayers.Geometry.Point(l,
n);q.transform(b,c);f.push(q);n+=p;q.y>=a.bottom&&!m&&(m=q)}this.labelled&&(m=new OpenLayers.Geometry.Point(m.x,a.bottom),l={value:l,label:this.labelled?OpenLayers.Util.getFormattedLonLat(l,"lon",this.labelFormat):"",labelAlign:"cb",xOffset:0,yOffset:2},this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(m,l)));f=new OpenLayers.Geometry.LineString(f);g.push(new OpenLayers.Feature.Vector(f))}for(h=0;h<e.length;++h)if(n=e[h].y,!(-90>n||90<n)){f=[];d=k[0].x;p=(k[k.length-1].x-d)/this.numPoints;
l=d;m=null;for(d=0;d<=this.numPoints;++d)q=new OpenLayers.Geometry.Point(l,n),q.transform(b,c),f.push(q),l+=p,q.x<a.right&&(m=q);this.labelled&&(m=new OpenLayers.Geometry.Point(a.right,m.y),l={value:n,label:this.labelled?OpenLayers.Util.getFormattedLonLat(n,"lat",this.labelFormat):"",labelAlign:"rb",xOffset:-2,yOffset:2},this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(m,l)));f=new OpenLayers.Geometry.LineString(f);g.push(new OpenLayers.Feature.Vector(f))}this.gratLayer.addFeatures(g)}},CLASS_NAME:"OpenLayers.Control.Graticule"});OpenLayers.Console.warn("OpenLayers.Rico is deprecated");OpenLayers.Rico=OpenLayers.Rico||{};
OpenLayers.Rico.Corner={round:function(a,b){a=OpenLayers.Util.getElement(a);this._setOptions(b);var c=this.options.color;"fromElement"==this.options.color&&(c=this._background(a));var d=this.options.bgColor;"fromParent"==this.options.bgColor&&(d=this._background(a.offsetParent));this._roundCornersImpl(a,c,d)},changeColor:function(a,b){a.style.backgroundColor=b;for(var c=a.parentNode.getElementsByTagName("span"),d=0;d<c.length;d++)c[d].style.backgroundColor=b},changeOpacity:function(a,b){var c="alpha(opacity="+
100*b+")";a.style.opacity=b;a.style.filter=c;for(var d=a.parentNode.getElementsByTagName("span"),e=0;e<d.length;e++)d[e].style.opacity=b,d[e].style.filter=c},reRound:function(a,b){var c=a.parentNode.childNodes[2];a.parentNode.removeChild(a.parentNode.childNodes[0]);a.parentNode.removeChild(c);this.round(a.parentNode,b)},_roundCornersImpl:function(a,b,c){this.options.border&&this._renderBorder(a,c);this._isTopRounded()&&this._roundTopCorners(a,b,c);this._isBottomRounded()&&this._roundBottomCorners(a,
b,c)},_renderBorder:function(a,b){var c="1px solid "+this._borderColor(b);a.innerHTML="<div "+("style='border-left: "+c+";"+("border-right: "+c)+"'")+">"+a.innerHTML+"</div>"},_roundTopCorners:function(a,b,c){for(var d=this._createCorner(c),e=0;e<this.options.numSlices;e++)d.appendChild(this._createCornerSlice(b,c,e,"top"));a.style.paddingTop=0;a.insertBefore(d,a.firstChild)},_roundBottomCorners:function(a,b,c){for(var d=this._createCorner(c),e=this.options.numSlices-1;0<=e;e--)d.appendChild(this._createCornerSlice(b,
c,e,"bottom"));a.style.paddingBottom=0;a.appendChild(d)},_createCorner:function(a){var b=document.createElement("div");b.style.backgroundColor=this._isTransparent()?"transparent":a;return b},_createCornerSlice:function(a,b,c,d){var e=document.createElement("span"),f=e.style;f.backgroundColor=a;f.display="block";f.height="1px";f.overflow="hidden";f.fontSize="1px";a=this._borderColor(a,b);this.options.border&&0==c?(f.borderTopStyle="solid",f.borderTopWidth="1px",f.borderLeftWidth="0px",f.borderRightWidth=
"0px",f.borderBottomWidth="0px",f.height="0px",f.borderColor=a):a&&(f.borderColor=a,f.borderStyle="solid",f.borderWidth="0px 1px");this.options.compact||c!=this.options.numSlices-1||(f.height="2px");this._setMargin(e,c,d);this._setBorder(e,c,d);return e},_setOptions:function(a){this.options={corners:"all",color:"fromElement",bgColor:"fromParent",blend:!0,border:!1,compact:!1};OpenLayers.Util.extend(this.options,a||{});this.options.numSlices=this.options.compact?2:4;this._isTransparent()&&(this.options.blend=
!1)},_whichSideTop:function(){return this._hasString(this.options.corners,"all","top")||0<=this.options.corners.indexOf("tl")&&0<=this.options.corners.indexOf("tr")?"":0<=this.options.corners.indexOf("tl")?"left":0<=this.options.corners.indexOf("tr")?"right":""},_whichSideBottom:function(){return this._hasString(this.options.corners,"all","bottom")||0<=this.options.corners.indexOf("bl")&&0<=this.options.corners.indexOf("br")?"":0<=this.options.corners.indexOf("bl")?"left":0<=this.options.corners.indexOf("br")?
"right":""},_borderColor:function(a,b){return"transparent"==a?b:this.options.border?this.options.border:this.options.blend?this._blend(b,a):""},_setMargin:function(a,b,c){b=this._marginSize(b);c="top"==c?this._whichSideTop():this._whichSideBottom();"left"==c?(a.style.marginLeft=b+"px",a.style.marginRight="0px"):"right"==c?(a.style.marginRight=b+"px",a.style.marginLeft="0px"):(a.style.marginLeft=b+"px",a.style.marginRight=b+"px")},_setBorder:function(a,b,c){b=this._borderSize(b);c="top"==c?this._whichSideTop():
this._whichSideBottom();"left"==c?(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth="0px"):"right"==c?(a.style.borderRightWidth=b+"px",a.style.borderLeftWidth="0px"):(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px");!1!=this.options.border&&(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px")},_marginSize:function(a){if(this._isTransparent())return 0;var b=[5,3,2,1],c=[3,2,1,0],d=[2,1],e=[1,0];return this.options.compact&&this.options.blend?e[a]:this.options.compact?
d[a]:this.options.blend?c[a]:b[a]},_borderSize:function(a){var b=[5,3,2,1],c=[2,1,1,1],d=[1,0],e=[0,2,0,0];return this.options.compact&&(this.options.blend||this._isTransparent())?1:this.options.compact?d[a]:this.options.blend?c[a]:this.options.border?e[a]:this._isTransparent()?b[a]:0},_hasString:function(a){for(var b=1;b<arguments.length;b++)if(0<=a.indexOf(arguments[b]))return!0;return!1},_blend:function(a,b){var c=OpenLayers.Rico.Color.createFromHex(a);c.blend(OpenLayers.Rico.Color.createFromHex(b));
return c},_background:function(a){try{return OpenLayers.Rico.Color.createColorFromBackground(a).asHex()}catch(b){return"#ffffff"}},_isTransparent:function(){return"transparent"==this.options.color},_isTopRounded:function(){return this._hasString(this.options.corners,"all","top","tl","tr")},_isBottomRounded:function(){return this._hasString(this.options.corners,"all","bottom","bl","br")},_hasSingleTextChild:function(a){return 1==a.childNodes.length&&3==a.childNodes[0].nodeType}};OpenLayers.Control.NavigationHistory=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOGGLE,previous:null,previousOptions:null,next:null,nextOptions:null,limit:50,autoActivate:!0,clearOnDeactivate:!1,registry:null,nextStack:null,previousStack:null,listeners:null,restoring:!1,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.registry=OpenLayers.Util.extend({moveend:this.getState},this.registry);a={trigger:OpenLayers.Function.bind(this.previousTrigger,
this),displayClass:this.displayClass+" "+this.displayClass+"Previous"};OpenLayers.Util.extend(a,this.previousOptions);this.previous=new OpenLayers.Control.Button(a);a={trigger:OpenLayers.Function.bind(this.nextTrigger,this),displayClass:this.displayClass+" "+this.displayClass+"Next"};OpenLayers.Util.extend(a,this.nextOptions);this.next=new OpenLayers.Control.Button(a);this.clear()},onPreviousChange:function(a,b){a&&!this.previous.active?this.previous.activate():!a&&this.previous.active&&this.previous.deactivate()},
onNextChange:function(a,b){a&&!this.next.active?this.next.activate():!a&&this.next.active&&this.next.deactivate()},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this);this.previous.destroy();this.next.destroy();this.deactivate();for(var a in this)this[a]=null},setMap:function(a){this.map=a;this.next.setMap(a);this.previous.setMap(a)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.next.draw();this.previous.draw()},previousTrigger:function(){var a=this.previousStack.shift(),
b=this.previousStack.shift();void 0!=b?(this.nextStack.unshift(a),this.previousStack.unshift(b),this.restoring=!0,this.restore(b),this.restoring=!1,this.onNextChange(this.nextStack[0],this.nextStack.length),this.onPreviousChange(this.previousStack[1],this.previousStack.length-1)):this.previousStack.unshift(a);return b},nextTrigger:function(){var a=this.nextStack.shift();void 0!=a&&(this.previousStack.unshift(a),this.restoring=!0,this.restore(a),this.restoring=!1,this.onNextChange(this.nextStack[0],
this.nextStack.length),this.onPreviousChange(this.previousStack[1],this.previousStack.length-1));return a},clear:function(){this.previousStack=[];this.previous.deactivate();this.nextStack=[];this.next.deactivate()},getState:function(){return{center:this.map.getCenter(),resolution:this.map.getResolution(),projection:this.map.getProjectionObject(),units:this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units}},restore:function(a){var b,c;if(this.map.getProjectionObject()==
a.projection)c=this.map.getZoomForResolution(a.resolution),b=a.center;else{b=a.center.clone();b.transform(a.projection,this.map.getProjectionObject());c=a.units;var d=this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units;c=this.map.getZoomForResolution((c&&d?OpenLayers.INCHES_PER_UNIT[c]/OpenLayers.INCHES_PER_UNIT[d]:1)*a.resolution)}this.map.setCenter(b,c)},setListeners:function(){this.listeners={};for(var a in this.registry)this.listeners[a]=OpenLayers.Function.bind(function(){if(!this.restoring){var b=
this.registry[a].apply(this,arguments);this.previousStack.unshift(b);if(1<this.previousStack.length)this.onPreviousChange(this.previousStack[1],this.previousStack.length-1);this.previousStack.length>this.limit+1&&this.previousStack.pop();0<this.nextStack.length&&(this.nextStack=[],this.onNextChange(null,0))}return!0},this)},activate:function(){var a=!1;if(this.map&&OpenLayers.Control.prototype.activate.apply(this)){null==this.listeners&&this.setListeners();for(var b in this.listeners)this.map.events.register(b,
this,this.listeners[b]);a=!0;0==this.previousStack.length&&this.initStack()}return a},initStack:function(){this.map.getCenter()&&this.listeners.moveend()},deactivate:function(){var a=!1;if(this.map&&OpenLayers.Control.prototype.deactivate.apply(this)){for(var b in this.listeners)this.map.events.unregister(b,this,this.listeners[b]);this.clearOnDeactivate&&this.clear();a=!0}return a},CLASS_NAME:"OpenLayers.Control.NavigationHistory"});OpenLayers.Layer.UTFGrid=OpenLayers.Class(OpenLayers.Layer.XYZ,{isBaseLayer:!1,projection:new OpenLayers.Projection("EPSG:900913"),useJSONP:!1,tileClass:OpenLayers.Tile.UTFGrid,initialize:function(a){OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a.name,a.url,{},a]);this.tileOptions=OpenLayers.Util.extend({utfgridResolution:this.utfgridResolution},this.tileOptions)},createBackBuffer:function(){},clone:function(a){null==a&&(a=new OpenLayers.Layer.UTFGrid(this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
[a])},getFeatureInfo:function(a){var b=null;(a=this.getTileData(a))&&a.tile&&(b=a.tile.getFeatureInfo(a.i,a.j));return b},getFeatureId:function(a){var b=null;a=this.getTileData(a);a.tile&&(b=a.tile.getFeatureId(a.i,a.j));return b},CLASS_NAME:"OpenLayers.Layer.UTFGrid"});OpenLayers.TileManager=OpenLayers.Class({cacheSize:256,tilesPerFrame:2,frameDelay:16,moveDelay:100,zoomDelay:200,maps:null,tileQueueId:null,tileQueue:null,tileCache:null,tileCacheIndex:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.maps=[];this.tileQueueId={};this.tileQueue={};this.tileCache={};this.tileCacheIndex=[]},addMap:function(a){if(!this._destroyed&&OpenLayers.Layer.Grid){this.maps.push(a);this.tileQueue[a.id]=[];for(var b=0,c=a.layers.length;b<c;++b)this.addLayer({layer:a.layers[b]});
a.events.on({move:this.move,zoomend:this.zoomEnd,changelayer:this.changeLayer,addlayer:this.addLayer,preremovelayer:this.removeLayer,scope:this})}},removeMap:function(a){if(!this._destroyed&&OpenLayers.Layer.Grid){window.clearTimeout(this.tileQueueId[a.id]);if(a.layers)for(var b=0,c=a.layers.length;b<c;++b)this.removeLayer({layer:a.layers[b]});a.events&&a.events.un({move:this.move,zoomend:this.zoomEnd,changelayer:this.changeLayer,addlayer:this.addLayer,preremovelayer:this.removeLayer,scope:this});
delete this.tileQueue[a.id];delete this.tileQueueId[a.id];OpenLayers.Util.removeItem(this.maps,a)}},move:function(a){this.updateTimeout(a.object,this.moveDelay,!0)},zoomEnd:function(a){this.updateTimeout(a.object,this.zoomDelay)},changeLayer:function(a){"visibility"!==a.property&&"params"!==a.property||this.updateTimeout(a.object,0)},addLayer:function(a){a=a.layer;if(a instanceof OpenLayers.Layer.Grid){a.events.on({addtile:this.addTile,retile:this.clearTileQueue,scope:this});var b,c,d;for(b=a.grid.length-
1;0<=b;--b)for(c=a.grid[b].length-1;0<=c;--c)d=a.grid[b][c],this.addTile({tile:d}),d.url&&this.manageTileCache({object:d})}},removeLayer:function(a){a=a.layer;if(a instanceof OpenLayers.Layer.Grid&&(this.clearTileQueue({object:a}),a.events&&a.events.un({addtile:this.addTile,retile:this.clearTileQueue,scope:this}),a.grid)){var b,c,d;for(b=a.grid.length-1;0<=b;--b)for(c=a.grid[b].length-1;0<=c;--c)d=a.grid[b][c],this.unloadTile({object:d}),d.url&&this.manageTileCache({object:d})}},updateTimeout:function(a,
b,c){window.clearTimeout(this.tileQueueId[a.id]);var d=this.tileQueue[a.id];if(!c||d.length)this.tileQueueId[a.id]=window.setTimeout(OpenLayers.Function.bind(function(){this.drawTilesFromQueue(a);d.length&&this.updateTimeout(a,this.frameDelay)},this),b)},addTile:function(a){a.tile.events.on({beforedraw:this.queueTileDraw,beforeload:this.manageTileCache,loadend:this.addToCache,unload:this.unloadTile,scope:this})},unloadTile:function(a){a=a.object;a.events.un({beforedraw:this.queueTileDraw,beforeload:this.manageTileCache,
loadend:this.addToCache,unload:this.unloadTile,scope:this});OpenLayers.Util.removeItem(this.tileQueue[a.layer.map.id],a)},queueTileDraw:function(a){a=a.object;var b=!1,c=a.layer,d=c.getURL(a.bounds),e=this.tileCache[d];e&&"olTileImage"!==e.className&&(delete this.tileCache[d],OpenLayers.Util.removeItem(this.tileCacheIndex,d),e=null);!c.url||!c.async&&e||(b=this.tileQueue[c.map.id],~OpenLayers.Util.indexOf(b,a)||b.push(a),b=!0);return!b},drawTilesFromQueue:function(a){var b=this.tileQueue[a.id],c=
this.tilesPerFrame;for(a=a.zoomTween&&a.zoomTween.playing;!a&&b.length&&c;)b.shift().draw(!0),--c},manageTileCache:function(a){a=a.object;var b=this.tileCache[a.url];if(b&&(!b.parentNode||OpenLayers.Element.hasClass(b.parentNode,"olBackBuffer"))){if(a.layer.backBuffer){if(a.layer.backBuffer===b.parentNode)return;b.style.opacity=0;b.style.visibility="hidden"}b.id=null;a.setImage(b);OpenLayers.Util.removeItem(this.tileCacheIndex,a.url);this.tileCacheIndex.push(a.url)}},addToCache:function(a){a=a.object;
this.tileCache[a.url]||OpenLayers.Element.hasClass(a.imgDiv,"olImageLoadError")||(this.tileCacheIndex.length>=this.cacheSize&&(delete this.tileCache[this.tileCacheIndex[0]],this.tileCacheIndex.shift()),this.tileCache[a.url]=a.imgDiv,this.tileCacheIndex.push(a.url))},clearTileQueue:function(a){a=a.object;for(var b=this.tileQueue[a.map.id],c=b.length-1;0<=c;--c)b[c].layer===a&&b.splice(c,1)},destroy:function(){for(var a=this.maps.length-1;0<=a;--a)this.removeMap(this.maps[a]);this.tileCacheIndex=this.tileCache=
this.tileQueueId=this.tileQueue=this.maps=null;this._destroyed=!0}});OpenLayers.Layer.ArcGISCache=OpenLayers.Class(OpenLayers.Layer.XYZ,{url:null,tileOrigin:null,tileSize:new OpenLayers.Size(256,256),useArcGISServer:!0,type:"png",useScales:!1,overrideDPI:!1,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.resolutions&&(this.serverResolutions=this.resolutions,this.maxExtent=this.getMaxExtentForResolution(this.resolutions[0]));if(this.layerInfo){var d=this.layerInfo,e=new OpenLayers.Bounds(d.fullExtent.xmin,d.fullExtent.ymin,
d.fullExtent.xmax,d.fullExtent.ymax);this.projection="EPSG:"+d.spatialReference.wkid;this.sphericalMercator=102100==d.spatialReference.wkid;this.units="esriFeet"==d.units?"ft":"m";if(d.tileInfo){this.tileSize=new OpenLayers.Size(d.tileInfo.width||d.tileInfo.cols,d.tileInfo.height||d.tileInfo.rows);this.tileOrigin=new OpenLayers.LonLat(d.tileInfo.origin.x,d.tileInfo.origin.y);var f=new OpenLayers.Geometry.Point(e.left,e.top),e=new OpenLayers.Geometry.Point(e.right,e.bottom);this.useScales?this.scales=
[]:this.resolutions=[];this.lods=[];for(var g in d.tileInfo.lods)if(d.tileInfo.lods.hasOwnProperty(g)){var h=d.tileInfo.lods[g];this.useScales?this.scales.push(h.scale):this.resolutions.push(h.resolution);var k=this.getContainingTileCoords(f,h.resolution);h.startTileCol=k.x;h.startTileRow=k.y;k=this.getContainingTileCoords(e,h.resolution);h.endTileCol=k.x;h.endTileRow=k.y;this.lods.push(h)}this.maxExtent=this.calculateMaxExtentWithLOD(this.lods[0]);this.serverResolutions=this.resolutions;this.overrideDPI&&
d.tileInfo.dpi&&(OpenLayers.DOTS_PER_INCH=d.tileInfo.dpi)}}},getContainingTileCoords:function(a,b){return new OpenLayers.Pixel(Math.max(Math.floor((a.x-this.tileOrigin.lon)/(this.tileSize.w*b)),0),Math.max(Math.floor((this.tileOrigin.lat-a.y)/(this.tileSize.h*b)),0))},calculateMaxExtentWithLOD:function(a){var b=this.tileOrigin.lon+a.startTileCol*this.tileSize.w*a.resolution,c=this.tileOrigin.lat-a.startTileRow*this.tileSize.h*a.resolution;return new OpenLayers.Bounds(b,c-(a.endTileRow-a.startTileRow+
1)*this.tileSize.h*a.resolution,b+(a.endTileCol-a.startTileCol+1)*this.tileSize.w*a.resolution,c)},calculateMaxExtentWithExtent:function(a,b){var c=new OpenLayers.Geometry.Point(a.left,a.top),d=new OpenLayers.Geometry.Point(a.right,a.bottom),c=this.getContainingTileCoords(c,b),d=this.getContainingTileCoords(d,b);return this.calculateMaxExtentWithLOD({resolution:b,startTileCol:c.x,startTileRow:c.y,endTileCol:d.x,endTileRow:d.y})},getUpperLeftTileCoord:function(a){var b=new OpenLayers.Geometry.Point(this.maxExtent.left,
this.maxExtent.top);return this.getContainingTileCoords(b,a)},getLowerRightTileCoord:function(a){var b=new OpenLayers.Geometry.Point(this.maxExtent.right,this.maxExtent.bottom);return this.getContainingTileCoords(b,a)},getMaxExtentForResolution:function(a){var b=this.getUpperLeftTileCoord(a),c=this.getLowerRightTileCoord(a),d=this.tileOrigin.lon+b.x*this.tileSize.w*a,e=this.tileOrigin.lat-b.y*this.tileSize.h*a;return new OpenLayers.Bounds(d,e-(c.y-b.y+1)*this.tileSize.h*a,d+(c.x-b.x+1)*this.tileSize.w*
a,e)},clone:function(a){null==a&&(a=new OpenLayers.Layer.ArcGISCache(this.name,this.url,this.options));return OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},initGriddedTiles:function(a){delete this._tileOrigin;OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this,arguments)},getMaxExtent:function(){var a=this.map.getResolution();return this.maxExtent=this.getMaxExtentForResolution(a)},getTileOrigin:function(){if(!this._tileOrigin){var a=this.getMaxExtent();this._tileOrigin=new OpenLayers.LonLat(a.left,
a.bottom)}return this._tileOrigin},getURL:function(a){var b=this.getResolution(),c=this.tileOrigin.lon+b*this.tileSize.w/2,d=this.tileOrigin.lat-b*this.tileSize.h/2;a=a.getCenterLonLat();c=Math.round(Math.abs((a.lon-c)/(b*this.tileSize.w)));d=Math.round(Math.abs((d-a.lat)/(b*this.tileSize.h)));a=this.map.getZoom();if(this.lods){if(b=this.lods[this.map.getZoom()],c<b.startTileCol||c>b.endTileCol||d<b.startTileRow||d>b.endTileRow)return null}else{var e=this.getUpperLeftTileCoord(b),b=this.getLowerRightTileCoord(b);
if(c<e.x||c>=b.x||d<e.y||d>=b.y)return null}b=this.url;e=""+c+d+a;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(e,b));this.useArcGISServer?b+="/tile/${z}/${y}/${x}":(c="C"+OpenLayers.Number.zeroPad(c,8,16),d="R"+OpenLayers.Number.zeroPad(d,8,16),a="L"+OpenLayers.Number.zeroPad(a,2,10),b=b+"/${z}/${y}/${x}."+this.type);b=OpenLayers.String.format(b,{x:c,y:d,z:a});return OpenLayers.Util.urlAppend(b,OpenLayers.Util.getParameterString(this.params))},CLASS_NAME:"OpenLayers.Layer.ArcGISCache"});OpenLayers.Control.WMSGetFeatureInfo=OpenLayers.Class(OpenLayers.Control,{hover:!1,drillDown:!1,maxFeatures:10,clickCallback:"click",output:"features",layers:null,queryVisible:!1,url:null,layerUrls:null,infoFormat:"text/html",vendorParams:{},format:null,formatOptions:null,handler:null,hoverRequest:null,initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.format||(this.format=new OpenLayers.Format.WMSGetFeatureInfo(a.formatOptions));
!0===this.drillDown&&(this.hover=!1);this.hover?this.handler=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.getInfoForHover},OpenLayers.Util.extend(this.handlerOptions.hover||{},{delay:250})):(a={},a[this.clickCallback]=this.getInfoForClick,this.handler=new OpenLayers.Handler.Click(this,a,this.handlerOptions.click||{}))},getInfoForClick:function(a){this.events.triggerEvent("beforegetfeatureinfo",{xy:a.xy});OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");this.request(a.xy,
{})},getInfoForHover:function(a){this.events.triggerEvent("beforegetfeatureinfo",{xy:a.xy});this.request(a.xy,{hover:!0})},cancelHover:function(){this.hoverRequest&&(this.hoverRequest.abort(),this.hoverRequest=null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d,e=a.length-1;0<=e;--e)c=a[e],c instanceof OpenLayers.Layer.WMS&&(!this.queryVisible||c.getVisibility())&&(d=OpenLayers.Util.isArray(c.url)?c.url[0]:c.url,!1!==this.drillDown||this.url||(this.url=d),(!0===this.drillDown||
this.urlMatches(d))&&b.push(c));return b},urlMatches:function(a){var b=OpenLayers.Util.isEquivalentUrl(this.url,a);if(!b&&this.layerUrls)for(var c=0,d=this.layerUrls.length;c<d;++c)if(OpenLayers.Util.isEquivalentUrl(this.layerUrls[c],a)){b=!0;break}return b},buildWMSOptions:function(a,b,c,d){for(var e=[],f=[],g=0,h=b.length;g<h;g++)null!=b[g].params.LAYERS&&(e=e.concat(b[g].params.LAYERS),f=f.concat(this.getStyleNames(b[g])));b=b[0];g=this.map.getProjection();(h=b.projection)&&h.equals(this.map.getProjectionObject())&&
(g=h.getCode());d=OpenLayers.Util.extend({service:"WMS",version:b.params.VERSION,request:"GetFeatureInfo",exceptions:b.params.EXCEPTIONS,bbox:this.map.getExtent().toBBOX(null,b.reverseAxisOrder()),feature_count:this.maxFeatures,height:this.map.getSize().h,width:this.map.getSize().w,format:d,info_format:b.params.INFO_FORMAT||this.infoFormat},1.3<=parseFloat(b.params.VERSION)?{crs:g,i:parseInt(c.x),j:parseInt(c.y)}:{srs:g,x:parseInt(c.x),y:parseInt(c.y)});0!=e.length&&(d=OpenLayers.Util.extend({layers:e,
query_layers:e,styles:f},d));OpenLayers.Util.applyDefaults(d,this.vendorParams);return{url:a,params:OpenLayers.Util.upperCaseObject(d),callback:function(b){this.handleResponse(c,b,a)},scope:this}},getStyleNames:function(a){return a.params.STYLES?a.params.STYLES:OpenLayers.Util.isArray(a.params.LAYERS)?Array(a.params.LAYERS.length):a.params.LAYERS.replace(/[^,]/g,"")},request:function(a,b){var c=this.findLayers();if(0==c.length)this.events.triggerEvent("nogetfeatureinfo"),OpenLayers.Element.removeClass(this.map.viewPortDiv,
"olCursorWait");else if(b=b||{},!1===this.drillDown){var c=this.buildWMSOptions(this.url,c,a,c[0].params.FORMAT),d=OpenLayers.Request.GET(c);!0===b.hover&&(this.hoverRequest=d)}else{this._numRequests=this._requestCount=0;this.features=[];for(var d={},e,f=0,g=c.length;f<g;f++){var h=c[f];e=OpenLayers.Util.isArray(h.url)?h.url[0]:h.url;e in d?d[e].push(h):(this._numRequests++,d[e]=[h])}for(e in d)c=d[e],c=this.buildWMSOptions(e,c,a,c[0].params.FORMAT),OpenLayers.Request.GET(c)}},triggerGetFeatureInfo:function(a,
b,c){this.events.triggerEvent("getfeatureinfo",{text:a.responseText,features:c,request:a,xy:b});OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait")},handleResponse:function(a,b,c){var d=b.responseXML;d&&d.documentElement||(d=b.responseText);d=this.format.read(d);!1===this.drillDown?this.triggerGetFeatureInfo(b,a,d):(this._requestCount++,this._features="object"===this.output?(this._features||[]).concat({url:c,features:d}):(this._features||[]).concat(d),this._requestCount===this._numRequests&&
(this.triggerGetFeatureInfo(b,a,this._features.concat()),delete this._features,delete this._requestCount,delete this._numRequests))},CLASS_NAME:"OpenLayers.Control.WMSGetFeatureInfo"});OpenLayers.Format.WMSCapabilities.v1_3_0=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_3,{version:"1.3.0",CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_3_0"});OpenLayers.Format.SOSGetFeatureOfInterest=OpenLayers.Class(OpenLayers.Format.XML,{VERSION:"1.0.0",namespaces:{sos:"http://www.opengis.net/sos/1.0",gml:"http://www.opengis.net/gml",sa:"http://www.opengis.net/sampling/1.0",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd",defaultPrefix:"sos",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a){"string"==
typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={features:[]};this.readNode(a,b);a=[];for(var c=0,d=b.features.length;c<d;c++){var e=b.features[c];this.internalProjection&&(this.externalProjection&&e.components[0])&&e.components[0].transform(this.externalProjection,this.internalProjection);e=new OpenLayers.Feature.Vector(e.components[0],e.attributes);a.push(e)}return a},readers:{sa:{SamplingPoint:function(a,b){if(!b.attributes){var c=
{attributes:{}};b.features.push(c);b=c}b.attributes.id=this.getAttributeNS(a,this.namespaces.gml,"id");this.readChildNodes(a,b)},position:function(a,b){this.readChildNodes(a,b)}},gml:OpenLayers.Util.applyDefaults({FeatureCollection:function(a,b){this.readChildNodes(a,b)},featureMember:function(a,b){var c={attributes:{}};b.features.push(c);this.readChildNodes(a,c)},name:function(a,b){b.attributes.name=this.getChildValue(a)},pos:function(a,b){this.externalProjection||(this.externalProjection=new OpenLayers.Projection(a.getAttribute("srsName")));
OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this,[a,b])}},OpenLayers.Format.GML.v3.prototype.readers.gml)},writers:{sos:{GetFeatureOfInterest:function(a){for(var b=this.createElementNSPlus("GetFeatureOfInterest",{attributes:{version:this.VERSION,service:"SOS","xsi:schemaLocation":this.schemaLocation}}),c=0,d=a.fois.length;c<d;c++)this.writeNode("FeatureOfInterestId",{foi:a.fois[c]},b);return b},FeatureOfInterestId:function(a){return this.createElementNSPlus("FeatureOfInterestId",{value:a.foi})}}},
CLASS_NAME:"OpenLayers.Format.SOSGetFeatureOfInterest"});OpenLayers.Format.SOSGetObservation=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows",gml:"http://www.opengis.net/gml",sos:"http://www.opengis.net/sos/1.0",ogc:"http://www.opengis.net/ogc",om:"http://www.opengis.net/om/1.0",sa:"http://www.opengis.net/sampling/1.0",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd",
defaultPrefix:"sos",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={measurements:[],observations:[]};this.readNode(a,b);return b},write:function(a){a=this.writeNode("sos:GetObservation",a);a.setAttribute("xmlns:om",this.namespaces.om);a.setAttribute("xmlns:ogc",this.namespaces.ogc);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,
[a])},readers:{om:{ObservationCollection:function(a,b){b.id=this.getAttributeNS(a,this.namespaces.gml,"id");this.readChildNodes(a,b)},member:function(a,b){this.readChildNodes(a,b)},Measurement:function(a,b){var c={};b.measurements.push(c);this.readChildNodes(a,c)},Observation:function(a,b){var c={};b.observations.push(c);this.readChildNodes(a,c)},samplingTime:function(a,b){var c={};b.samplingTime=c;this.readChildNodes(a,c)},observedProperty:function(a,b){b.observedProperty=this.getAttributeNS(a,this.namespaces.xlink,
"href");this.readChildNodes(a,b)},procedure:function(a,b){b.procedure=this.getAttributeNS(a,this.namespaces.xlink,"href");this.readChildNodes(a,b)},featureOfInterest:function(a,b){var c={features:[]};b.fois=[];b.fois.push(c);this.readChildNodes(a,c);for(var d=[],e=0,f=c.features.length;e<f;e++){var g=c.features[e];d.push(new OpenLayers.Feature.Vector(g.components[0],g.attributes))}c.features=d},result:function(a,b){var c={};b.result=c;""!==this.getChildValue(a)?(c.value=this.getChildValue(a),c.uom=
a.getAttribute("uom")):this.readChildNodes(a,c)}},sa:OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa,gml:OpenLayers.Util.applyDefaults({TimeInstant:function(a,b){var c={};b.timeInstant=c;this.readChildNodes(a,c)},timePosition:function(a,b){b.timePosition=this.getChildValue(a)}},OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml)},writers:{sos:{GetObservation:function(a){var b=this.createElementNSPlus("GetObservation",{attributes:{version:this.VERSION,service:"SOS"}});this.writeNode("offering",
a,b);a.eventTime&&this.writeNode("eventTime",a,b);for(var c in a.procedures)this.writeNode("procedure",a.procedures[c],b);for(var d in a.observedProperties)this.writeNode("observedProperty",a.observedProperties[d],b);a.foi&&this.writeNode("featureOfInterest",a.foi,b);this.writeNode("responseFormat",a,b);a.resultModel&&this.writeNode("resultModel",a,b);a.responseMode&&this.writeNode("responseMode",a,b);return b},featureOfInterest:function(a){var b=this.createElementNSPlus("featureOfInterest");this.writeNode("ObjectID",
a.objectId,b);return b},ObjectID:function(a){return this.createElementNSPlus("ObjectID",{value:a})},responseFormat:function(a){return this.createElementNSPlus("responseFormat",{value:a.responseFormat})},procedure:function(a){return this.createElementNSPlus("procedure",{value:a})},offering:function(a){return this.createElementNSPlus("offering",{value:a.offering})},observedProperty:function(a){return this.createElementNSPlus("observedProperty",{value:a})},eventTime:function(a){var b=this.createElementNSPlus("eventTime");
"latest"===a.eventTime&&this.writeNode("ogc:TM_Equals",a,b);return b},resultModel:function(a){return this.createElementNSPlus("resultModel",{value:a.resultModel})},responseMode:function(a){return this.createElementNSPlus("responseMode",{value:a.responseMode})}},ogc:{TM_Equals:function(a){var b=this.createElementNSPlus("ogc:TM_Equals");this.writeNode("ogc:PropertyName",{property:"urn:ogc:data:time:iso8601"},b);"latest"===a.eventTime&&this.writeNode("gml:TimeInstant",{value:"latest"},b);return b},PropertyName:function(a){return this.createElementNSPlus("ogc:PropertyName",
{value:a.property})}},gml:{TimeInstant:function(a){var b=this.createElementNSPlus("gml:TimeInstant");this.writeNode("gml:timePosition",a,b);return b},timePosition:function(a){return this.createElementNSPlus("gml:timePosition",{value:a.value})}}},CLASS_NAME:"OpenLayers.Format.SOSGetObservation"});OpenLayers.Control.UTFGrid=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,layers:null,defaultHandlerOptions:{delay:300,pixelTolerance:4,stopMove:!1,single:!0,"double":!1,stopSingle:!1,stopDouble:!1},handlerMode:"click",setHandler:function(a){this.handlerMode=a;this.resetHandler()},resetHandler:function(){this.handler&&(this.handler.deactivate(),this.handler.destroy(),this.handler=null);"hover"==this.handlerMode?this.handler=new OpenLayers.Handler.Hover(this,{pause:this.handleEvent,move:this.reset},
this.handlerOptions):"click"==this.handlerMode?this.handler=new OpenLayers.Handler.Click(this,{click:this.handleEvent},this.handlerOptions):"move"==this.handlerMode&&(this.handler=new OpenLayers.Handler.Hover(this,{pause:this.handleEvent,move:this.handleEvent},this.handlerOptions));return this.handler?!0:!1},initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||this.defaultHandlerOptions;OpenLayers.Control.prototype.initialize.apply(this,[a]);this.resetHandler()},handleEvent:function(a){if(null==
a)this.reset();else{var b=this.map.getLonLatFromPixel(a.xy);if(b){var c=this.findLayers();if(0<c.length){for(var d={},e,f,g=0,h=c.length;g<h;g++)e=c[g],f=OpenLayers.Util.indexOf(this.map.layers,e),d[f]=e.getFeatureInfo(b);this.callback(d,b,a.xy)}}}},callback:function(a){},reset:function(a){this.callback(null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d=a.length-1;0<=d;--d)c=a[d],c instanceof OpenLayers.Layer.UTFGrid&&b.push(c);return b},CLASS_NAME:"OpenLayers.Control.UTFGrid"});OpenLayers.Format.CQL=function(){function a(a){function b(){var a=e.pop();switch(a.type){case "LOGICAL":var c=b(),g=b();return new OpenLayers.Filter.Logical({filters:[g,c],type:f[a.text.toUpperCase()]});case "NOT":return a=b(),new OpenLayers.Filter.Logical({filters:[a],type:OpenLayers.Filter.Logical.NOT});case "BETWEEN":return e.pop(),g=b(),a=b(),c=b(),new OpenLayers.Filter.Comparison({property:c,lowerBoundary:a,upperBoundary:g,type:OpenLayers.Filter.Comparison.BETWEEN});case "COMPARISON":return g=
b(),c=b(),new OpenLayers.Filter.Comparison({property:c,value:g,type:d[a.text.toUpperCase()]});case "IS_NULL":return c=b(),new OpenLayers.Filter.Comparison({property:c,type:d[a.text.toUpperCase()]});case "VALUE":return(c=a.text.match(/^'(.*)'$/))?c[1].replace(/''/g,"'"):Number(a.text);case "SPATIAL":switch(a.text.toUpperCase()){case "BBOX":var a=b(),c=b(),g=b(),h=b(),k=b();return new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,property:k,value:OpenLayers.Bounds.fromArray([h,g,c,
a])});case "INTERSECTS":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:c,value:g});case "WITHIN":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.WITHIN,property:c,value:g});case "CONTAINS":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.CONTAINS,property:c,value:g});case "DWITHIN":return a=b(),g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,value:g,
property:c,distance:Number(a)})}case "GEOMETRY":return OpenLayers.Geometry.fromWKT(a.text);default:return a.text}}for(var c=[],e=[];a.length;){var g=a.shift();switch(g.type){case "PROPERTY":case "GEOMETRY":case "VALUE":e.push(g);break;case "COMPARISON":case "BETWEEN":case "IS_NULL":case "LOGICAL":for(var k=h[g.type];0<c.length&&h[c[c.length-1].type]<=k;)e.push(c.pop());c.push(g);break;case "SPATIAL":case "NOT":case "LPAREN":c.push(g);break;case "RPAREN":for(;0<c.length&&"LPAREN"!=c[c.length-1].type;)e.push(c.pop());
c.pop();0<c.length&&"SPATIAL"==c[c.length-1].type&&e.push(c.pop());case "COMMA":case "END":break;default:throw Error("Unknown token type "+g.type);}}for(;0<c.length;)e.push(c.pop());a=b();if(0<e.length){a="Remaining tokens after building AST: \n";for(c=e.length-1;0<=c;c--)a+=e[c].type+": "+e[c].text+"\n";throw Error(a);}return a}var b={PROPERTY:/^[_a-zA-Z]\w*/,COMPARISON:/^(=|<>|<=|<|>=|>|LIKE)/i,IS_NULL:/^IS NULL/i,COMMA:/^,/,LOGICAL:/^(AND|OR)/i,VALUE:/^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/,LPAREN:/^\(/,
RPAREN:/^\)/,SPATIAL:/^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i,NOT:/^NOT/i,BETWEEN:/^BETWEEN/i,GEOMETRY:function(a){var b=/^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(a);if(b){var c=a.length,b=a.indexOf("(",b[0].length);if(-1<b)for(var d=1;b<c&&0<d;)switch(b++,a.charAt(b)){case "(":d++;break;case ")":d--}return[a.substr(0,b+1)]}},END:/^$/},c={LPAREN:["GEOMETRY","SPATIAL","PROPERTY","VALUE","LPAREN"],RPAREN:["NOT","LOGICAL","END","RPAREN"],PROPERTY:["COMPARISON",
"BETWEEN","COMMA","IS_NULL"],BETWEEN:["VALUE"],IS_NULL:["END"],COMPARISON:["VALUE"],COMMA:["GEOMETRY","VALUE","PROPERTY"],VALUE:["LOGICAL","COMMA","RPAREN","END"],SPATIAL:["LPAREN"],LOGICAL:["NOT","VALUE","SPATIAL","PROPERTY","LPAREN"],NOT:["PROPERTY","LPAREN"],GEOMETRY:["COMMA","RPAREN"]},d={"=":OpenLayers.Filter.Comparison.EQUAL_TO,"<>":OpenLayers.Filter.Comparison.NOT_EQUAL_TO,"<":OpenLayers.Filter.Comparison.LESS_THAN,"<=":OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO,">":OpenLayers.Filter.Comparison.GREATER_THAN,
">=":OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO,LIKE:OpenLayers.Filter.Comparison.LIKE,BETWEEN:OpenLayers.Filter.Comparison.BETWEEN,"IS NULL":OpenLayers.Filter.Comparison.IS_NULL},e={},f={AND:OpenLayers.Filter.Logical.AND,OR:OpenLayers.Filter.Logical.OR},g={},h={RPAREN:3,LOGICAL:2,COMPARISON:1},k;for(k in d)d.hasOwnProperty(k)&&(e[d[k]]=k);for(k in f)f.hasOwnProperty(k)&&(g[f[k]]=k);return OpenLayers.Class(OpenLayers.Format,{read:function(d){var e=d;d=[];var f,g=["NOT","GEOMETRY","SPATIAL",
"PROPERTY","LPAREN"];do{a:{f=g;for(var h=void 0,g=void 0,k=f.length,h=0;h<k;h++){var g=f[h],s=b[g]instanceof RegExp?b[g].exec(e):(0,b[g])(e);if(s){f=s[0];e=e.substr(f.length).replace(/^\s*/,"");f={type:g,text:f,remainder:e};break a}}d="ERROR: In parsing: ["+e+"], expected one of: ";for(h=0;h<k;h++)g=f[h],d+="\n    "+g+": "+b[g];throw Error(d);}e=f.remainder;g=c[f.type];if("END"!=f.type&&!g)throw Error("No follows list for "+f.type);d.push(f)}while("END"!=f.type);d=a(d);this.keepData&&(this.data=d);
return d},write:function(a){if(a instanceof OpenLayers.Geometry)return a.toString();switch(a.CLASS_NAME){case "OpenLayers.Filter.Spatial":switch(a.type){case OpenLayers.Filter.Spatial.BBOX:return"BBOX("+a.property+","+a.value.toBBOX()+")";case OpenLayers.Filter.Spatial.DWITHIN:return"DWITHIN("+a.property+", "+this.write(a.value)+", "+a.distance+")";case OpenLayers.Filter.Spatial.WITHIN:return"WITHIN("+a.property+", "+this.write(a.value)+")";case OpenLayers.Filter.Spatial.INTERSECTS:return"INTERSECTS("+
a.property+", "+this.write(a.value)+")";case OpenLayers.Filter.Spatial.CONTAINS:return"CONTAINS("+a.property+", "+this.write(a.value)+")";default:throw Error("Unknown spatial filter type: "+a.type);}case "OpenLayers.Filter.Logical":if(a.type==OpenLayers.Filter.Logical.NOT)return"NOT ("+this.write(a.filters[0])+")";for(var b="(",c=!0,d=0;d<a.filters.length;d++)c?c=!1:b+=") "+g[a.type]+" (",b+=this.write(a.filters[d]);return b+")";case "OpenLayers.Filter.Comparison":return a.type==OpenLayers.Filter.Comparison.BETWEEN?
a.property+" BETWEEN "+this.write(a.lowerBoundary)+" AND "+this.write(a.upperBoundary):null!==a.value?a.property+" "+e[a.type]+" "+this.write(a.value):a.property+" "+e[a.type];case void 0:if("string"===typeof a)return"'"+a.replace(/'/g,"''")+"'";if("number"===typeof a)return String(a);default:throw Error("Can't encode: "+a.CLASS_NAME+" "+a);}},CLASS_NAME:"OpenLayers.Format.CQL"})}();OpenLayers.Control.Split=OpenLayers.Class(OpenLayers.Control,{layer:null,source:null,sourceOptions:null,tolerance:null,edge:!0,deferDelete:!1,mutual:!0,targetFilter:null,sourceFilter:null,handler:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.options=a||{};this.options.source&&this.setSource(this.options.source)},setSource:function(a){this.active?(this.deactivate(),this.handler&&(this.handler.destroy(),delete this.handler),this.source=a,this.activate()):this.source=
a},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a)if(!this.source)this.handler||(this.handler=new OpenLayers.Handler.Path(this,{done:function(a){this.onSketchComplete({feature:new OpenLayers.Feature.Vector(a)})}},{layerOptions:this.sourceOptions})),this.handler.activate();else if(this.source.events)this.source.events.on({sketchcomplete:this.onSketchComplete,afterfeaturemodified:this.afterFeatureModified,scope:this});return a},deactivate:function(){var a=OpenLayers.Control.prototype.deactivate.call(this);
a&&this.source&&this.source.events&&this.source.events.un({sketchcomplete:this.onSketchComplete,afterfeaturemodified:this.afterFeatureModified,scope:this});return a},onSketchComplete:function(a){this.feature=null;return!this.considerSplit(a.feature)},afterFeatureModified:function(a){a.modified&&"function"===typeof a.feature.geometry.split&&(this.feature=a.feature,this.considerSplit(a.feature))},removeByGeometry:function(a,b){for(var c=0,d=a.length;c<d;++c)if(a[c].geometry===b){a.splice(c,1);break}},
isEligible:function(a){return a.geometry?a.state!==OpenLayers.State.DELETE&&"function"===typeof a.geometry.split&&this.feature!==a&&(!this.targetFilter||this.targetFilter.evaluate(a.attributes)):!1},considerSplit:function(a){var b=!1,c=!1;if(!this.sourceFilter||this.sourceFilter.evaluate(a.attributes)){for(var d=this.layer&&this.layer.features||[],e,f,g=[],h=[],k=this.layer===this.source&&this.mutual,l={edge:this.edge,tolerance:this.tolerance,mutual:k},m=[a.geometry],n,p,q,r=0,s=d.length;r<s;++r)if(n=
d[r],this.isEligible(n)){p=[n.geometry];for(var t=0;t<m.length;++t){q=m[t];for(var u=0;u<p.length;++u)if(e=p[u],q.getBounds().intersectsBounds(e.getBounds())&&(e=q.split(e,l)))f=this.events.triggerEvent("beforesplit",{source:a,target:n}),!1!==f&&(k&&(f=e[0],1<f.length&&(f.unshift(t,1),Array.prototype.splice.apply(m,f),t+=f.length-3),e=e[1]),1<e.length&&(e.unshift(u,1),Array.prototype.splice.apply(p,e),u+=e.length-3))}p&&1<p.length&&(this.geomsToFeatures(n,p),this.events.triggerEvent("split",{original:n,
features:p}),Array.prototype.push.apply(g,p),h.push(n),c=!0)}m&&1<m.length&&(this.geomsToFeatures(a,m),this.events.triggerEvent("split",{original:a,features:m}),Array.prototype.push.apply(g,m),h.push(a),b=!0);if(b||c){if(this.deferDelete){d=[];r=0;for(s=h.length;r<s;++r)c=h[r],c.state===OpenLayers.State.INSERT?d.push(c):(c.state=OpenLayers.State.DELETE,this.layer.drawFeature(c));this.layer.destroyFeatures(d,{silent:!0});r=0;for(s=g.length;r<s;++r)g[r].state=OpenLayers.State.INSERT}else this.layer.destroyFeatures(h,
{silent:!0});this.layer.addFeatures(g,{silent:!0});this.events.triggerEvent("aftersplit",{source:a,features:g})}}return b},geomsToFeatures:function(a,b){var c=a.clone();delete c.geometry;for(var d,e=0,f=b.length;e<f;++e)d=c.clone(),d.geometry=b[e],d.state=OpenLayers.State.INSERT,b[e]=d},destroy:function(){this.active&&this.deactivate();OpenLayers.Control.prototype.destroy.call(this)},CLASS_NAME:"OpenLayers.Control.Split"});OpenLayers.Layer.WMTS=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,version:"1.0.0",requestEncoding:"KVP",url:null,layer:null,matrixSet:null,style:null,format:"image/jpeg",tileOrigin:null,tileFullExtent:null,formatSuffix:null,matrixIds:null,dimensions:null,params:null,zoomOffset:0,serverResolutions:null,formatSuffixMap:{"image/png":"png","image/png8":"png","image/png24":"png","image/png32":"png",png:"png","image/jpeg":"jpg","image/jpg":"jpg",jpeg:"jpg",jpg:"jpg"},matrix:null,initialize:function(a){var b=
{url:!0,layer:!0,style:!0,matrixSet:!0},c;for(c in b)if(!(c in a))throw Error("Missing property '"+c+"' in layer configuration.");a.params=OpenLayers.Util.upperCaseObject(a.params);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a.name,a.url,a.params,a]);this.formatSuffix||(this.formatSuffix=this.formatSuffixMap[this.format]||this.format.split("/").pop());if(this.matrixIds&&(a=this.matrixIds.length)&&"string"===typeof this.matrixIds[0])for(b=this.matrixIds,this.matrixIds=Array(a),c=0;c<a;++c)this.matrixIds[c]=
{identifier:b[c]}},setMap:function(){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments)},updateMatrixProperties:function(){if(this.matrix=this.getMatrix())this.matrix.topLeftCorner&&(this.tileOrigin=this.matrix.topLeftCorner),this.matrix.tileWidth&&this.matrix.tileHeight&&(this.tileSize=new OpenLayers.Size(this.matrix.tileWidth,this.matrix.tileHeight)),this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.top)),this.tileFullExtent||(this.tileFullExtent=
this.maxExtent)},moveTo:function(a,b,c){!b&&this.matrix||this.updateMatrixProperties();return OpenLayers.Layer.Grid.prototype.moveTo.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMTS(this.options));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getIdentifier:function(){return this.getServerZoom()},getMatrix:function(){var a;if(this.matrixIds&&0!==this.matrixIds.length)if("scaleDenominator"in this.matrixIds[0])for(var b=OpenLayers.METERS_PER_INCH*OpenLayers.INCHES_PER_UNIT[this.units]*
this.getServerResolution()/2.8E-4,c=Number.POSITIVE_INFINITY,d,e=0,f=this.matrixIds.length;e<f;++e)d=Math.abs(1-this.matrixIds[e].scaleDenominator/b),d<c&&(c=d,a=this.matrixIds[e]);else a=this.matrixIds[this.getIdentifier()];else a={identifier:this.getIdentifier()};return a},getTileInfo:function(a){var b=this.getServerResolution(),c=(a.lon-this.tileOrigin.lon)/(b*this.tileSize.w);a=(this.tileOrigin.lat-a.lat)/(b*this.tileSize.h);var b=Math.floor(c),d=Math.floor(a);return{col:b,row:d,i:Math.floor((c-
b)*this.tileSize.w),j:Math.floor((a-d)*this.tileSize.h)}},getURL:function(a){a=this.adjustBounds(a);var b="";if(!this.tileFullExtent||this.tileFullExtent.intersectsBounds(a)){a=a.getCenterLonLat();var c=this.getTileInfo(a);a=this.dimensions;var d,b=OpenLayers.Util.isArray(this.url)?this.selectUrl([this.version,this.style,this.matrixSet,this.matrix.identifier,c.row,c.col].join(),this.url):this.url;if("REST"===this.requestEncoding.toUpperCase())if(d=this.params,-1!==b.indexOf("{")){b=b.replace(/\{/g,
"${");c={style:this.style,Style:this.style,TileMatrixSet:this.matrixSet,TileMatrix:this.matrix.identifier,TileRow:c.row,TileCol:c.col};if(a){var e,f;for(f=a.length-1;0<=f;--f)e=a[f],c[e]=d[e.toUpperCase()]}b=OpenLayers.String.format(b,c)}else{e=this.version+"/"+this.layer+"/"+this.style+"/";if(a)for(f=0;f<a.length;f++)d[a[f]]&&(e=e+d[a[f]]+"/");e=e+this.matrixSet+"/"+this.matrix.identifier+"/"+c.row+"/"+c.col+"."+this.formatSuffix;b.match(/\/$/)||(b+="/");b+=e}else"KVP"===this.requestEncoding.toUpperCase()&&
(d={SERVICE:"WMTS",REQUEST:"GetTile",VERSION:this.version,LAYER:this.layer,STYLE:this.style,TILEMATRIXSET:this.matrixSet,TILEMATRIX:this.matrix.identifier,TILEROW:c.row,TILECOL:c.col,FORMAT:this.format},b=OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,[d]))}return b},mergeNewParams:function(a){if("KVP"===this.requestEncoding.toUpperCase())return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,[OpenLayers.Util.upperCaseObject(a)])},CLASS_NAME:"OpenLayers.Layer.WMTS"});OpenLayers.Protocol.SOS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol,{fois:null,formatOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=new OpenLayers.Format.SOSGetFeatureOfInterest(this.formatOptions))},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,this.options||
{});var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.format,c=OpenLayers.Format.XML.prototype.write.apply(c,[c.writeNode("sos:GetFeatureOfInterest",{fois:this.fois})]);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),data:c});return b},handleRead:function(a,b){if(b.callback){var c=a.priv;200<=c.status&&300>c.status?(a.features=this.parseFeatures(c),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE;
b.callback.call(b.scope,a)}},parseFeatures:function(a){var b=a.responseXML;b&&b.documentElement||(b=a.responseText);return!b||0>=b.length?null:this.format.read(b)},CLASS_NAME:"OpenLayers.Protocol.SOS.v1_0_0"});OpenLayers.Layer.KaMapCache=OpenLayers.Class(OpenLayers.Layer.KaMap,{IMAGE_EXTENSIONS:{jpeg:"jpg",gif:"gif",png:"png",png8:"png",png24:"png",dithered:"png"},DEFAULT_FORMAT:"jpeg",initialize:function(a,b,c,d){OpenLayers.Layer.KaMap.prototype.initialize.apply(this,arguments);this.extension=this.IMAGE_EXTENSIONS[this.params.i.toLowerCase()||this.DEFAULT_FORMAT]},getURL:function(a){a=this.adjustBounds(a);var b=this.map.getResolution(),c=Math.round(1E4*this.map.getScale())/1E4,d=Math.round(a.left/b);a=
-Math.round(a.top/b);var b=Math.floor(d/this.tileSize.w/this.params.metaTileSize.w)*this.tileSize.w*this.params.metaTileSize.w,e=Math.floor(a/this.tileSize.h/this.params.metaTileSize.h)*this.tileSize.h*this.params.metaTileSize.h,c=["/",this.params.map,"/",c,"/",this.params.g.replace(/\s/g,"_"),"/def/t",e,"/l",b,"/t",a,"l",d,".",this.extension],d=this.url;OpenLayers.Util.isArray(d)&&(d=this.selectUrl(c.join(""),d));return d+c.join("")},CLASS_NAME:"OpenLayers.Layer.KaMapCache"});OpenLayers.Protocol.WFS.v1_1_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.1.0",initialize:function(a){OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this,arguments);this.outputFormat&&!this.readFormat&&("gml2"==this.outputFormat.toLowerCase()?this.readFormat=new OpenLayers.Format.GML.v2({featureType:this.featureType,featureNS:this.featureNS,geometryName:this.geometryName}):"json"==this.outputFormat.toLowerCase()&&(this.readFormat=new OpenLayers.Format.GeoJSON))},CLASS_NAME:"OpenLayers.Protocol.WFS.v1_1_0"});OpenLayers.Format.WMSCapabilities.v1_1_1=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1,{version:"1.1.1",readers:{wms:OpenLayers.Util.applyDefaults({SRS:function(a,b){b.srs[this.getChildValue(a)]=!0}},OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_1"});OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1_1,{version:"1.1.1",profile:"WMSC",readers:{wms:OpenLayers.Util.applyDefaults({VendorSpecificCapabilities:function(a,b){b.vendorSpecific={tileSets:[]};this.readChildNodes(a,b.vendorSpecific)},TileSet:function(a,b){var c={srs:{},bbox:{},resolutions:[]};this.readChildNodes(a,c);b.tileSets.push(c)},Resolutions:function(a,b){for(var c=this.getChildValue(a).split(" "),d=0,e=c.length;d<e;d++)""!=c[d]&&b.resolutions.push(parseFloat(c[d]))},
Width:function(a,b){b.width=parseInt(this.getChildValue(a))},Height:function(a,b){b.height=parseInt(this.getChildValue(a))},Layers:function(a,b){b.layers=this.getChildValue(a)},Styles:function(a,b){b.styles=this.getChildValue(a)}},OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC"});OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:!0,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[]},destroy:function(){this.clearLayersArray("base");this.clearLayersArray("data");this.map.events.un({buttonclick:this.onButtonClick,addlayer:this.redraw,changelayer:this.redraw,
removelayer:this.redraw,changebaselayer:this.redraw,scope:this});this.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});this.outsideViewport?(this.events.attachToElement(this.div),this.events.register("buttonclick",this,this.onButtonClick)):
this.map.events.register("buttonclick",this,this.onButtonClick)},draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();this.outsideViewport||this.minimizeControl();this.redraw();return this.div},onButtonClick:function(a){a=a.buttonElement;a===this.minimizeDiv?this.minimizeControl():a===this.maximizeDiv?this.maximizeControl():a._layerSwitcher===this.id&&(a["for"]&&(a=document.getElementById(a["for"])),a.disabled||("radio"==a.type?(a.checked=!0,this.map.setBaseLayer(this.map.getLayer(a._layer))):
(a.checked=!a.checked,this.updateMap())))},clearLayersArray:function(a){this[a+"LayersDiv"].innerHTML="";this[a+"Layers"]=[]},checkRedraw:function(){if(!this.layerStates.length||this.map.layers.length!=this.layerStates.length)return!0;for(var a=0,b=this.layerStates.length;a<b;a++){var c=this.layerStates[a],d=this.map.layers[a];if(c.name!=d.name||c.inRange!=d.inRange||c.id!=d.id||c.visibility!=d.visibility)return!0}return!1},redraw:function(){if(!this.checkRedraw())return this.div;this.clearLayersArray("base");
this.clearLayersArray("data");var a=!1,b=!1,c=this.map.layers.length;this.layerStates=Array(c);for(var d=0;d<c;d++){var e=this.map.layers[d];this.layerStates[d]={name:e.name,visibility:e.visibility,inRange:e.inRange,id:e.id}}var f=this.map.layers.slice();this.ascending||f.reverse();d=0;for(c=f.length;d<c;d++){var e=f[d],g=e.isBaseLayer;if(e.displayInLayerSwitcher){g?b=!0:a=!0;var h=g?e==this.map.baseLayer:e.getVisibility(),k=document.createElement("input"),l=OpenLayers.Util.createUniqueID(this.id+
"_input_");k.id=l;k.name=g?this.id+"_baseLayers":e.name;k.type=g?"radio":"checkbox";k.value=e.name;k.checked=h;k.defaultChecked=h;k.className="olButton";k._layer=e.id;k._layerSwitcher=this.id;g||e.inRange||(k.disabled=!0);h=document.createElement("label");h["for"]=k.id;OpenLayers.Element.addClass(h,"labelSpan olButton");h._layer=e.id;h._layerSwitcher=this.id;g||e.inRange||(h.style.color="gray");h.innerHTML=e.name;h.style.verticalAlign=g?"bottom":"baseline";l=document.createElement("br");(g?this.baseLayers:
this.dataLayers).push({layer:e,inputElem:k,labelSpan:h});e=g?this.baseLayersDiv:this.dataLayersDiv;e.appendChild(k);e.appendChild(h);e.appendChild(l)}}this.dataLbl.style.display=a?"":"none";this.baseLbl.style.display=b?"":"none";return this.div},updateMap:function(){for(var a=0,b=this.baseLayers.length;a<b;a++){var c=this.baseLayers[a];c.inputElem.checked&&this.map.setBaseLayer(c.layer,!1)}a=0;for(b=this.dataLayers.length;a<b;a++)c=this.dataLayers[a],c.layer.setVisibility(c.inputElem.checked)},maximizeControl:function(a){this.div.style.width=
"";this.div.style.height="";this.showControls(!1);null!=a&&OpenLayers.Event.stop(a)},minimizeControl:function(a){this.div.style.width="0px";this.div.style.height="0px";this.showControls(!0);null!=a&&OpenLayers.Event.stop(a)},showControls:function(a){this.maximizeDiv.style.display=a?"":"none";this.minimizeDiv.style.display=a?"none":"";this.layersDiv.style.display=a?"none":""},loadContents:function(){this.layersDiv=document.createElement("div");this.layersDiv.id=this.id+"_layersDiv";OpenLayers.Element.addClass(this.layersDiv,
"layersDiv");this.baseLbl=document.createElement("div");this.baseLbl.innerHTML=OpenLayers.i18n("Base Layer");OpenLayers.Element.addClass(this.baseLbl,"baseLbl");this.baseLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.baseLayersDiv,"baseLayersDiv");this.dataLbl=document.createElement("div");this.dataLbl.innerHTML=OpenLayers.i18n("Overlays");OpenLayers.Element.addClass(this.dataLbl,"dataLbl");this.dataLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.dataLayersDiv,
"dataLayersDiv");this.ascending?(this.layersDiv.appendChild(this.baseLbl),this.layersDiv.appendChild(this.baseLayersDiv),this.layersDiv.appendChild(this.dataLbl),this.layersDiv.appendChild(this.dataLayersDiv)):(this.layersDiv.appendChild(this.dataLbl),this.layersDiv.appendChild(this.dataLayersDiv),this.layersDiv.appendChild(this.baseLbl),this.layersDiv.appendChild(this.baseLayersDiv));this.div.appendChild(this.layersDiv);var a=OpenLayers.Util.getImageLocation("layer-switcher-maximize.png");this.maximizeDiv=
OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv",null,null,a,"absolute");OpenLayers.Element.addClass(this.maximizeDiv,"maximizeDiv olButton");this.maximizeDiv.style.display="none";this.div.appendChild(this.maximizeDiv);a=OpenLayers.Util.getImageLocation("layer-switcher-minimize.png");this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv",null,null,a,"absolute");OpenLayers.Element.addClass(this.minimizeDiv,"minimizeDiv olButton");this.minimizeDiv.style.display=
"none";this.div.appendChild(this.minimizeDiv)},CLASS_NAME:"OpenLayers.Control.LayerSwitcher"});OpenLayers.Format.Atom=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{atom:"http://www.w3.org/2005/Atom",georss:"http://www.georss.org/georss"},feedTitle:"untitled",defaultEntryTitle:"untitled",gmlParser:null,xy:!1,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));return this.parseFeatures(a)},write:function(a){var b;if(OpenLayers.Util.isArray(a)){b=this.createElementNSPlus("atom:feed");b.appendChild(this.createElementNSPlus("atom:title",{value:this.feedTitle}));
for(var c=0,d=a.length;c<d;c++)b.appendChild(this.buildEntryNode(a[c]))}else b=this.buildEntryNode(a);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},buildContentNode:function(a){var b=this.createElementNSPlus("atom:content",{attributes:{type:a.type||null}});if(a.src)b.setAttribute("src",a.src);else if("text"==a.type||null==a.type)b.appendChild(this.createTextNode(a.value));else if("html"==a.type){if("string"!=typeof a.value)throw"HTML content must be in form of an escaped string";b.appendChild(this.createTextNode(a.value))}else"xhtml"==
a.type?b.appendChild(a.value):"xhtml"==a.type||a.type.match(/(\+|\/)xml$/)?b.appendChild(a.value):b.appendChild(this.createTextNode(a.value));return b},buildEntryNode:function(a){var b=a.attributes,c=b.atom||{},d=this.createElementNSPlus("atom:entry");if(c.authors)for(var e=OpenLayers.Util.isArray(c.authors)?c.authors:[c.authors],f=0,g=e.length;f<g;f++)d.appendChild(this.buildPersonConstructNode("author",e[f]));if(c.categories)for(var e=OpenLayers.Util.isArray(c.categories)?c.categories:[c.categories],
h,f=0,g=e.length;f<g;f++)h=e[f],d.appendChild(this.createElementNSPlus("atom:category",{attributes:{term:h.term,scheme:h.scheme||null,label:h.label||null}}));c.content&&d.appendChild(this.buildContentNode(c.content));if(c.contributors)for(e=OpenLayers.Util.isArray(c.contributors)?c.contributors:[c.contributors],f=0,g=e.length;f<g;f++)d.appendChild(this.buildPersonConstructNode("contributor",e[f]));a.fid&&d.appendChild(this.createElementNSPlus("atom:id",{value:a.fid}));if(c.links)for(e=OpenLayers.Util.isArray(c.links)?
c.links:[c.links],f=0,g=e.length;f<g;f++)h=e[f],d.appendChild(this.createElementNSPlus("atom:link",{attributes:{href:h.href,rel:h.rel||null,type:h.type||null,hreflang:h.hreflang||null,title:h.title||null,length:h.length||null}}));c.published&&d.appendChild(this.createElementNSPlus("atom:published",{value:c.published}));c.rights&&d.appendChild(this.createElementNSPlus("atom:rights",{value:c.rights}));(c.summary||b.description)&&d.appendChild(this.createElementNSPlus("atom:summary",{value:c.summary||
b.description}));d.appendChild(this.createElementNSPlus("atom:title",{value:c.title||b.title||this.defaultEntryTitle}));c.updated&&d.appendChild(this.createElementNSPlus("atom:updated",{value:c.updated}));a.geometry&&(b=this.createElementNSPlus("georss:where"),b.appendChild(this.buildGeometryNode(a.geometry)),d.appendChild(b));return d},initGmlParser:function(){this.gmlParser=new OpenLayers.Format.GML.v3({xy:this.xy,featureNS:"http://example.com#feature",internalProjection:this.internalProjection,
externalProjection:this.externalProjection})},buildGeometryNode:function(a){this.gmlParser||this.initGmlParser();return this.gmlParser.writeNode("feature:_geometry",a).firstChild},buildPersonConstructNode:function(a,b){var c=["uri","email"],d=this.createElementNSPlus("atom:"+a);d.appendChild(this.createElementNSPlus("atom:name",{value:b.name}));for(var e=0,f=c.length;e<f;e++)b[c[e]]&&d.appendChild(this.createElementNSPlus("atom:"+c[e],{value:b[c[e]]}));return d},getFirstChildValue:function(a,b,c,
d){return(a=this.getElementsByTagNameNS(a,b,c))&&0<a.length?this.getChildValue(a[0],d):d},parseFeature:function(a){var b={},c=null,d=null,e=null,f=this.namespaces.atom;this.parsePersonConstructs(a,"author",b);d=this.getElementsByTagNameNS(a,f,"category");0<d.length&&(b.categories=[]);for(var g=0,h=d.length;g<h;g++){c={};c.term=d[g].getAttribute("term");if(e=d[g].getAttribute("scheme"))c.scheme=e;if(e=d[g].getAttribute("label"))c.label=e;b.categories.push(c)}d=this.getElementsByTagNameNS(a,f,"content");
if(0<d.length){c={};if(e=d[0].getAttribute("type"))c.type=e;(e=d[0].getAttribute("src"))?c.src=e:("text"==c.type||"html"==c.type||null==c.type?c.value=this.getFirstChildValue(a,f,"content",null):"xhtml"==c.type||c.type.match(/(\+|\/)xml$/)?c.value=this.getChildEl(d[0]):c.value=this.getFirstChildValue(a,f,"content",null),b.content=c)}this.parsePersonConstructs(a,"contributor",b);b.id=this.getFirstChildValue(a,f,"id",null);d=this.getElementsByTagNameNS(a,f,"link");0<d.length&&(b.links=Array(d.length));
for(var k=["rel","type","hreflang","title","length"],g=0,h=d.length;g<h;g++){c={};c.href=d[g].getAttribute("href");for(var l=0,m=k.length;l<m;l++)(e=d[g].getAttribute(k[l]))&&(c[k[l]]=e);b.links[g]=c}if(c=this.getFirstChildValue(a,f,"published",null))b.published=c;if(c=this.getFirstChildValue(a,f,"rights",null))b.rights=c;if(c=this.getFirstChildValue(a,f,"summary",null))b.summary=c;b.title=this.getFirstChildValue(a,f,"title",null);b.updated=this.getFirstChildValue(a,f,"updated",null);c={title:b.title,
description:b.summary,atom:b};a=this.parseLocations(a)[0];a=new OpenLayers.Feature.Vector(a,c);a.fid=b.id;return a},parseFeatures:function(a){var b=[],c=this.getElementsByTagNameNS(a,this.namespaces.atom,"entry");0==c.length&&(c=[a]);a=0;for(var d=c.length;a<d;a++)b.push(this.parseFeature(c[a]));return b},parseLocations:function(a){var b=this.namespaces.georss,c={components:[]},d=this.getElementsByTagNameNS(a,b,"where");if(d&&0<d.length){this.gmlParser||this.initGmlParser();for(var e=0,f=d.length;e<
f;e++)this.gmlParser.readChildNodes(d[e],c)}c=c.components;if((d=this.getElementsByTagNameNS(a,b,"point"))&&0<d.length)for(e=0,f=d.length;e<f;e++){var g=OpenLayers.String.trim(d[e].firstChild.nodeValue).split(/\s+/);2!=g.length&&(g=OpenLayers.String.trim(d[e].firstChild.nodeValue).split(/\s*,\s*/));c.push(new OpenLayers.Geometry.Point(g[1],g[0]))}var h=this.getElementsByTagNameNS(a,b,"line");if(h&&0<h.length)for(var k,e=0,f=h.length;e<f;e++){d=OpenLayers.String.trim(h[e].firstChild.nodeValue).split(/\s+/);
k=[];for(var l=0,m=d.length;l<m;l+=2)g=new OpenLayers.Geometry.Point(d[l+1],d[l]),k.push(g);c.push(new OpenLayers.Geometry.LineString(k))}if((a=this.getElementsByTagNameNS(a,b,"polygon"))&&0<a.length)for(e=0,f=a.length;e<f;e++){d=OpenLayers.String.trim(a[e].firstChild.nodeValue).split(/\s+/);k=[];l=0;for(m=d.length;l<m;l+=2)g=new OpenLayers.Geometry.Point(d[l+1],d[l]),k.push(g);c.push(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(k)]))}if(this.internalProjection&&this.externalProjection)for(e=
0,f=c.length;e<f;e++)c[e]&&c[e].transform(this.externalProjection,this.internalProjection);return c},parsePersonConstructs:function(a,b,c){var d=[],e=this.namespaces.atom;a=this.getElementsByTagNameNS(a,e,b);for(var f=["uri","email"],g=0,h=a.length;g<h;g++){var k={};k.name=this.getFirstChildValue(a[g],e,"name",null);for(var l=0,m=f.length;l<m;l++){var n=this.getFirstChildValue(a[g],e,f[l],null);n&&(k[f[l]]=n)}d.push(k)}0<d.length&&(c[b+"s"]=d)},CLASS_NAME:"OpenLayers.Format.Atom"});OpenLayers.Control.KeyboardDefaults=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,slideFactor:75,observeElement:null,draw:function(){this.handler=new OpenLayers.Handler.Keyboard(this,{keydown:this.defaultKeyPress},{observeElement:this.observeElement||document})},defaultKeyPress:function(a){var b,c=!0;b=OpenLayers.Event.element(a);if(!b||"INPUT"!=b.tagName&&"TEXTAREA"!=b.tagName&&"SELECT"!=b.tagName){switch(a.keyCode){case OpenLayers.Event.KEY_LEFT:this.map.pan(-this.slideFactor,0);break;case OpenLayers.Event.KEY_RIGHT:this.map.pan(this.slideFactor,
0);break;case OpenLayers.Event.KEY_UP:this.map.pan(0,-this.slideFactor);break;case OpenLayers.Event.KEY_DOWN:this.map.pan(0,this.slideFactor);break;case 33:b=this.map.getSize();this.map.pan(0,-0.75*b.h);break;case 34:b=this.map.getSize();this.map.pan(0,0.75*b.h);break;case 35:b=this.map.getSize();this.map.pan(0.75*b.w,0);break;case 36:b=this.map.getSize();this.map.pan(-0.75*b.w,0);break;case 43:case 61:case 187:case 107:this.map.zoomIn();break;case 45:case 109:case 189:case 95:this.map.zoomOut();
break;default:c=!1}c&&OpenLayers.Event.stop(a)}},CLASS_NAME:"OpenLayers.Control.KeyboardDefaults"});OpenLayers.Format.WMTSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1_1_0,{version:"1.0.0",namespaces:{ows:"http://www.opengis.net/ows/1.1",wmts:"http://www.opengis.net/wmts/1.0",xlink:"http://www.w3.org/1999/xlink"},yx:null,defaultPrefix:"wmts",initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.options=a;a=OpenLayers.Util.extend({},OpenLayers.Format.WMTSCapabilities.prototype.yx);this.yx=OpenLayers.Util.extend(a,this.yx)},read:function(a){"string"==
typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);b.version=this.version;return b},readers:{wmts:{Capabilities:function(a,b){this.readChildNodes(a,b)},Contents:function(a,b){b.contents={};b.contents.layers=[];b.contents.tileMatrixSets={};this.readChildNodes(a,b.contents)},Layer:function(a,b){var c={styles:[],formats:[],dimensions:[],tileMatrixSetLinks:[],layers:[]};this.readChildNodes(a,c);b.layers.push(c)},Style:function(a,
b){var c={};c.isDefault="true"===a.getAttribute("isDefault");this.readChildNodes(a,c);b.styles.push(c)},Format:function(a,b){b.formats.push(this.getChildValue(a))},TileMatrixSetLink:function(a,b){var c={};this.readChildNodes(a,c);b.tileMatrixSetLinks.push(c)},TileMatrixSet:function(a,b){if(b.layers){var c={matrixIds:[]};this.readChildNodes(a,c);b.tileMatrixSets[c.identifier]=c}else b.tileMatrixSet=this.getChildValue(a)},TileMatrix:function(a,b){var c={supportedCRS:b.supportedCRS};this.readChildNodes(a,
c);b.matrixIds.push(c)},ScaleDenominator:function(a,b){b.scaleDenominator=parseFloat(this.getChildValue(a))},TopLeftCorner:function(a,b){var c=this.getChildValue(a).split(" "),d;b.supportedCRS&&(d=b.supportedCRS.replace(/urn:ogc:def:crs:(\w+):.+:(\w+)$/,"urn:ogc:def:crs:$1::$2"),d=!!this.yx[d]);b.topLeftCorner=d?new OpenLayers.LonLat(c[1],c[0]):new OpenLayers.LonLat(c[0],c[1])},TileWidth:function(a,b){b.tileWidth=parseInt(this.getChildValue(a))},TileHeight:function(a,b){b.tileHeight=parseInt(this.getChildValue(a))},
MatrixWidth:function(a,b){b.matrixWidth=parseInt(this.getChildValue(a))},MatrixHeight:function(a,b){b.matrixHeight=parseInt(this.getChildValue(a))},ResourceURL:function(a,b){b.resourceUrl=b.resourceUrl||{};var c=a.getAttribute("resourceType");b.resourceUrls||(b.resourceUrls=[]);c=b.resourceUrl[c]={format:a.getAttribute("format"),template:a.getAttribute("template"),resourceType:c};b.resourceUrls.push(c)},WSDL:function(a,b){b.wsdl={};b.wsdl.href=a.getAttribute("xlink:href")},ServiceMetadataURL:function(a,
b){b.serviceMetadataUrl={};b.serviceMetadataUrl.href=a.getAttribute("xlink:href")},LegendURL:function(a,b){b.legend={};b.legend.href=a.getAttribute("xlink:href");b.legend.format=a.getAttribute("format")},Dimension:function(a,b){var c={values:[]};this.readChildNodes(a,c);b.dimensions.push(c)},Default:function(a,b){b["default"]=this.getChildValue(a)},Value:function(a,b){b.values.push(this.getChildValue(a))}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WMTSCapabilities.v1_0_0"});
/*
 * Patch che all'evento 'movestart' passa anche il valore dello zoom futuro
 */
 
OpenLayers.Map.prototype.moveTo = function(lonlat, zoom, options) {
	
        if (lonlat != null && !(lonlat instanceof OpenLayers.LonLat)) {
            lonlat = new OpenLayers.LonLat(lonlat);
        }
        if (!options) { 
            options = {};
        }
        if (zoom != null) {
            zoom = parseFloat(zoom);
            if (!this.fractionalZoom) {
                zoom = Math.round(zoom);
            }
        }
        var requestedZoom = zoom;
        zoom = this.adjustZoom(zoom);
        if (zoom !== requestedZoom) {
            // zoom was adjusted, so keep old lonlat to avoid panning
            lonlat = this.getCenter();
        }
        // dragging is false by default
        var dragging = options.dragging || this.dragging;
        // forceZoomChange is false by default
        var forceZoomChange = options.forceZoomChange;

        if (!this.getCachedCenter() && !this.isValidLonLat(lonlat)) {
            lonlat = this.maxExtent.getCenterLonLat();
            this.center = lonlat.clone();
        }

        if(this.restrictedExtent != null) {
            // In 3.0, decide if we want to change interpretation of maxExtent.
            if(lonlat == null) { 
                lonlat = this.center; 
            }
            if(zoom == null) { 
                zoom = this.getZoom(); 
            }
            var resolution = this.getResolutionForZoom(zoom);
            var extent = this.calculateBounds(lonlat, resolution); 
            if(!this.restrictedExtent.containsBounds(extent)) {
                var maxCenter = this.restrictedExtent.getCenterLonLat(); 
                if(extent.getWidth() > this.restrictedExtent.getWidth()) { 
                    lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat); 
                } else if(extent.left < this.restrictedExtent.left) {
                    lonlat = lonlat.add(this.restrictedExtent.left -
                                        extent.left, 0); 
                } else if(extent.right > this.restrictedExtent.right) { 
                    lonlat = lonlat.add(this.restrictedExtent.right -
                                        extent.right, 0); 
                } 
                if(extent.getHeight() > this.restrictedExtent.getHeight()) { 
                    lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat); 
                } else if(extent.bottom < this.restrictedExtent.bottom) { 
                    lonlat = lonlat.add(0, this.restrictedExtent.bottom -
                                        extent.bottom); 
                } 
                else if(extent.top > this.restrictedExtent.top) { 
                    lonlat = lonlat.add(0, this.restrictedExtent.top -
                                        extent.top); 
                } 
            }
        }
        
        var zoomChanged = forceZoomChange || (
                            (this.isValidZoomLevel(zoom)) && 
                            (zoom != this.getZoom()) );

        var centerChanged = (this.isValidLonLat(lonlat)) && 
                            (!lonlat.equals(this.center));

        // if neither center nor zoom will change, no need to do anything
        if (zoomChanged || centerChanged || dragging) {
            dragging || this.events.triggerEvent("movestart", {
                zoomChanged: zoomChanged,
                zoom: zoom
                //,zoom2: zoom
            });

            if (centerChanged) {
                if (!zoomChanged && this.center) { 
                    // if zoom hasnt changed, just slide layerContainer
                    //  (must be done before setting this.center to new value)
                    this.centerLayerContainer(lonlat);
                }
                this.center = lonlat.clone();
            }

            var res = zoomChanged ?
                this.getResolutionForZoom(zoom) : this.getResolution();
            // (re)set the layerContainerDiv's location
            if (zoomChanged || this.layerContainerOrigin == null) {
                this.layerContainerOrigin = this.getCachedCenter();
                this.layerContainerOriginPx.x = 0;
                this.layerContainerOriginPx.y = 0;
                this.applyTransform();
                var maxExtent = this.getMaxExtent({restricted: true});
                var maxExtentCenter = maxExtent.getCenterLonLat();
                var lonDelta = this.center.lon - maxExtentCenter.lon;
                var latDelta = maxExtentCenter.lat - this.center.lat;
                var extentWidth = Math.round(maxExtent.getWidth() / res);
                var extentHeight = Math.round(maxExtent.getHeight() / res);
                this.minPx = {
                    x: (this.size.w - extentWidth) / 2 - lonDelta / res,
                    y: (this.size.h - extentHeight) / 2 - latDelta / res
                };
                this.maxPx = {
                    x: this.minPx.x + Math.round(maxExtent.getWidth() / res),
                    y: this.minPx.y + Math.round(maxExtent.getHeight() / res)
                };
            }

            if (zoomChanged) {
                this.zoom = zoom;
                this.resolution = res;
            }    
            
            var bounds = this.getExtent();
            
            //send the move call to the baselayer and all the overlays    

            if(this.baseLayer.visibility) {
                this.baseLayer.moveTo(bounds, zoomChanged, options.dragging);
                options.dragging || this.baseLayer.events.triggerEvent(
                    "moveend", {zoomChanged: zoomChanged}
                );
            }
            
            bounds = this.baseLayer.getExtent();
            
            for (var i=this.layers.length-1; i>=0; --i) {
                var layer = this.layers[i];
                if (layer !== this.baseLayer && !layer.isBaseLayer) {
                    var inRange = layer.calculateInRange();
                    if (layer.inRange != inRange) {
                        // the inRange property has changed. If the layer is
                        // no longer in range, we turn it off right away. If
                        // the layer is no longer out of range, the moveTo
                        // call below will turn on the layer.
                        layer.inRange = inRange;
                        if (!inRange) {
                            layer.display(false);
                        }
						
						this.events.triggerEvent("changelayer", {
                            layer: layer, property: "visibility"
                        });
                    }
                    if (inRange && layer.visibility) {
                        layer.moveTo(bounds, zoomChanged, options.dragging);
                        options.dragging || layer.events.triggerEvent(
                            "moveend", {zoomChanged: zoomChanged}
                        );
                    }
                }                
            }
            
            this.events.triggerEvent("move");
            dragging || this.events.triggerEvent("moveend");

            if (zoomChanged) {
                //redraw popups
                for (var i=0, len=this.popups.length; i<len; i++) {
                    this.popups[i].updatePosition();
                }
                this.events.triggerEvent("zoomend");
            }
        }
    }
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */


/**
 * @requires OpenLayers/Handler/Point.js
 * @requires OpenLayers/Geometry/Point.js
 * @requires OpenLayers/Geometry/LineString.js
 */

/**
 * Class: OpenLayers.Handler.PointFromRef
 * Handler to draw a point that have a defined distance from another.  
 * Point of reference is set by mousedown. You can fix the distance by
 * the property defaultDistance, or set it by another mousedown.
 * After this step you can choose only the direction.
 *
 * Inherits from:
 *  - <OpenLayers.Handler.Point>
 */
OpenLayers.Handler.PointFromRef = OpenLayers.Class(OpenLayers.Handler.Point, {
    
    /**
     * Property: defaultDistance
     * {Number} This property fix the distance from th reference point.
     */
    defaultDistance: null,
        
    /**
     * Property: drawDistance
     * {Boolean} If true the Handler allows to set the distance from
     * reference point by a click of the mouse.
     */
    drawDistance: true,
    
    /**
     * Property: line
     * {<OpenLayers.Feature.Vector>}
     */
    line: null,
    
    infoOnMouse: true,
    
    /**
     * Method: setDistance
     * Set the distance from the point of reference.
     * This has no effect on defaultDistance
     *
     * Returns:
     * {Boolean}
     */
    setDistance: function (d){
    	this.distance = d;
    	if(this.drawing){
    		this.modifyFeature(); 
    		this.drawFeature();
    	}
    	this.callback("distance", [this.distance]);
    },

    /**
     * Constructor: OpenLayers.Handler.Path
     * Create a new path hander
     *
     * Parameters:
     * control - {<OpenLayers.Control>} 
     * callbacks - {Object} An object with a 'done' property whose value is a
     *     function to be called when the point drawing is finished. he callback should expect to recieve a single argument,
     *     the point geometry. 
     *     If the callbacks object contains a 'refPoint' property, 
     *     this function will be sent when the reference point is set.
     *     If the callbacks object contains a 'distance' property, 
     *     this function will be sent when the distance is set or when the distance
     *     is not set and the mousemove.
     *     If the callbacks object contains a
     *     'cancel' property, this function will be called when the
     *     handler is deactivated while drawing.   
     *     If the callbacks object contains a 'cancel' property, this function 
     *     will be called when the handler is deactivated while drawing. The 
     *     cancel should expect to receive a geometry.
     * options - {Object} An optional object with properties to be set on the
     *           handler
     */
    initialize: function(control, callbacks, options) {
    	    	
        OpenLayers.Handler.Point.prototype.initialize.apply(this, arguments);
        this.distance = null;    
        this.toFinalize = false;    
         // cache the bound event listener method so it can be unobserved later
        this.eventListener = OpenLayers.Function.bindAsEventListener(
            this.keydown, this
        );
        
    },
    
    /**
     * Metodo identico a quello del padre (Point)
     * L'unica modifica apportata � l'inversione delle operazioni 1 e 2 e l'aggiunta necessaria della 3
     * Potendo esserci il richiamo di una finestra modale sulla callback (alert, confirm, etc.)
     * non sparirebbero le linee di costruzione prima di aver risposto.
     */
    finalize: function(cancel) {
        var key = cancel ? "cancel" : "done";
        this.drawing = false;
        this.mouseDown = false;
        this.lastDown = null;
        this.lastUp = null;
        /* 3 */
        var clone = this.geometryClone();
        
        /* 2 */
        if(cancel || !this.persist) {
            this.destroyFeature();
        }
        /* 1 */
        this.callback(key, [clone]);
       
    },
    
    /**
     * APIMethod: activate
     * turn on the handler
     */
    activate: function() {
        if(OpenLayers.Handler.Point.prototype.activate.apply(this, arguments)) {
    		OpenLayers.Event.observe(
                    document, "keydown", this.eventListener);
                    /*
            if(this.defaultDistance){
            	this.distance = this.defaultDistance;
            }
            */
            return true;
        }else{
        	return false;
        }
    },
    
    /**
     * APIMethod: deactivate
     * turn off the handler
     */
    deactivate: function() {
    	var deactivated = false;
        if (OpenLayers.Handler.Point.prototype.deactivate.apply(this, arguments)) {
            OpenLayers.Event.stopObserving(document, "keydown", this.eventListener);                       
            deactivated = true;
        }
        return deactivated;        
    },
    
        
    /**
     * Method: createFeature
     * Add temporary geometries
     */   
    createFeature: function(pixel) { 
         var lonlat = this.control.map.getLonLatFromPixel(pixel); 
         this.point = new OpenLayers.Feature.Vector( 
             new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat) 
         ); 
         this.refPoint = new OpenLayers.Feature.Vector(
                                        new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat));
         this.finalPoint = new OpenLayers.Feature.Vector(
                                        new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat));
         this.line = new OpenLayers.Feature.Vector( 
             new OpenLayers.Geometry.LineString([this.refPoint.geometry]) 
         ); 
         
         if(this.infoOnMouse){
         	this.createInfoPopup(lonlat);
         }
         this.callback("create", [this.point.geometry, this.line]); 
         this.point.geometry.clearBounds(); 
         this.layer.addFeatures([this.line,this.refPoint,this.point,this.finalPoint], {silent: true}); 
     }, 
    
        
    /**
     * Method: destroyFeature
     * Destroy temporary geometries and reset distance
     */
    destroyFeature: function() {
    	 
        OpenLayers.Handler.Point.prototype.destroyFeature.apply(this);

        this.line = null;
        this.refPoint = null;
        this.finalPoint = null;     
        this.toFinalize = false;
        if(!this.defaultDistance){
        	this.distance = null;
        }else{
        	this.distance = this.defaultDistance;
        }
        
        if(this.popup){
        	this.destroyInfoPopup();
        }
    },
    
    /**
     * Method: addPoint
     * Add point to geometry.  Send the point index to override
     * the behavior of LinearRing that disregards adding duplicate points.
     */
    addPoint: function() {
        this.line.geometry.addComponent(this.point.geometry.clone(),
                                        this.line.geometry.components.length);
    },

    /**
     * Method: modifyFeature
     * Modify the existing geometry given the new point
     */
     
    modifyFeature: function(pixel) {
        var index = this.line.geometry.components.length - 1;
      
        // Creo sempre e comunque un clone, perch� Internet Explorer altrimenti fa cose strane
        // a basse scale
    	var tmpPoint = this.point.geometry.clone();
    	
    	
    	if(this.distance){   	
    		var scale = this.distance/this.point.geometry.distanceTo(this.refPoint.geometry);
    		tmpPoint.resize(scale,this.refPoint.geometry);  		    		
    	}
    	
    	this.finalPoint.geometry.x = tmpPoint.x;
    	this.finalPoint.geometry.y = tmpPoint.y;
    	this.line.geometry.components[index].x = tmpPoint.x;
    	this.line.geometry.components[index].y = tmpPoint.y; 
    	
    	if(this.infoOnMouse){
    		var d = this.distance?this.distance:(this.refPoint?this.refPoint.geometry.distanceTo(tmpPoint):0);
	    	// Per mettere il popup di informazione sul punto fissato e non sul mouse  
			if(pixel){
				var lonlat = {};
				lonlat.lon = tmpPoint.x;
				lonlat.lat = tmpPoint.y;	    		
	    		pixel = this.control.map.getPixelFromLonLat(lonlat);
			}   	
	    	this.updateInfoPopup(pixel,d);
    	}   	
      
        this.line.geometry.components[index].clearBounds();
    },
    
    /**
     * Method: drawFeature
     * Render geometries on the temporary layer.
     */
    drawFeature: function() {
        
        // se � stato impostato il punto di riferimento e la distanza
        // non mostro pi� il punto sotto il mouse       
        if(this.refPoint && this.distance){
        	this.layer.drawFeature(this.point, {
                strokeOpacity: 0,
                fillOpacity: 0
            });        	       
        }else{
        	this.layer.drawFeature(this.point, this.style);
        }
        this.layer.drawFeature(this.line, this.style);
        
        this.layer.drawFeature(this.refPoint, this.style);
        
        this.layer.drawFeature(this.finalPoint, this.style);
    },

    /**
     * Method: geometryClone
     * Return a clone of the relevant geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.LineString>}
     */    
    geometryClone: function() {
        return this.finalPoint.geometry.clone();
    },

    /**
     * Method: mousedown
     * Handle mouse down.  Add a new point to the geometry and
     * render it. Return determines whether to propagate the event on the map.
     * 
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns: 
     * {Boolean} Allow event propagation
     */
    mousedown: function(evt) {
        // ignore double-clicks
        if(!this.drawing) {
            this.createFeature(evt.xy);
        }
        this.mouseDown = true;
        this.lastDown = evt.xy;
        var lonlat = this.control.map.getLonLatFromPixel(evt.xy);

        if(!this.drawing){
        	this.point.geometry.x = lonlat.lon;
        	this.point.geometry.y = lonlat.lat;
        	//this.addPoint();
        	this.addPoint();
        	this.refPoint.geometry.x = lonlat.lon;
        	this.refPoint.geometry.y = lonlat.lat;
          	this.callback("refPoint", [this.point.geometry]);
          	// quando aggiungo il primo punto se c'� una distanza di default la setto
          	if(this.defaultDistance){
            	this.setDistance(this.defaultDistance);
            }
          	this.drawFeature();
        }else if(this.lastUp != null /*&& !this.lastUp.equals(evt.xy)*/){
        	// se la distanza � stata impostata
        	if(this.distance){
        		var scale = this.distance/this.point.geometry.distanceTo(this.refPoint.geometry);
        		this.finalPoint.geometry.x = lonlat.lon;
        		this.finalPoint.geometry.y = lonlat.lat;
        		this.finalPoint.geometry.resize(scale,this.refPoint.geometry);
        		this.toFinalize = true;
            	//this.finalize();
            	return false;            	
        	}
        	// se la distanza non � stata impostata ma � attivo il flag che mi permette di settarla con il click
        	else if(this.drawDistance){
        		//this.distance = this.point.geometry.distanceTo(this.refPoint.geometry);
        		this.setDistance(this.point.geometry.distanceTo(this.refPoint.geometry));             			
        	}
        }                
        this.drawing = true;
        return false;
    },

    /**
     * Method: mousemove
     * Handle mouse move.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     * 
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns: 
     * {Boolean} Allow event propagation
     */
    mousemove: function (evt) {
        if(this.drawing && !this.mouseDown) { 
            var lonlat = this.map.getLonLatFromPixel(evt.xy);
            this.point.geometry.x = lonlat.lon;
            this.point.geometry.y = lonlat.lat;
            
            var d = 0;
            
            if(this.distance){            	
            	//this.callback("distance", [this.distance]);
            	d = this.distance;
            }else{
            	d = this.point.geometry.distanceTo(this.refPoint.geometry);
            	this.callback("distance", [d]);            	
            }            
            //this.updateInfoPopup(evt.xy,d);
            this.modifyFeature(evt.xy);            
            this.drawFeature();
        }
        return true;
    },
    
    /**
     * Method: mouseup
     * Handle mouse up.  Send the latest point in the geometry to
     * the control. Return determines whether to propagate the event on the map.
     * 
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns: 
     * {Boolean} Allow event propagation
     */
    mouseup: function (evt) {
        this.mouseDown = false;
        if(this.drawing) {
        	if(this.toFinalize){   
        		// finalizzo sul mouse up e poi comincio a ritrasmettere gli eventi     		
	        	this.finalize();        		
        	}else{
	            this.lastUp = evt.xy;            
        	}
        	return false;
        }
        return true;
    },
    
    keydown: function(evt){
    	if(evt.keyCode == 46 /* Canc */ || (evt.ctrlKey && evt.keyCode == 90) /* Ctrl + z */){
    		if(this.drawing){
    			if(!this.drawDistance || !this.distance){
    				this.cancel();
    			}else{
    				this.setDistance(null);
    				this.callback("distance", [this.point.geometry.distanceTo(this.refPoint.geometry)]);    				
    			}
    		}
    		return false;	
    	}
    	return true;
    },
    
    createInfoPopup: function(lonlat){
		if(this.popup){
			this.destroyInfoPopup();
		}
		this.popup = new OpenLayers.Popup.Anchored("infoOnMouse",lonlat,new OpenLayers.Size(100,30),"",{size : new OpenLayers.Size(0,0), offset : new OpenLayers.Pixel(0,0)});
        this.popup.setOpacity(0.6);
        this.popup.setBorder("solid black 1px");        
        this.control.map.addPopup(this.popup);
        this.updateInfoPopup(null,0);
	},
	
	destroyInfoPopup: function(){
		this.control.map.removePopup(this.popup);
		this.popup.destroy();
		this.popup = null;
	},
	
	updateInfoPopup: function(pixel,distance){
		
		this.popup.hide();      
				
		var html  = "<div>Distance = " + Math.round(distance*100)/100 + "</div>";
		    		    
        this.popup.setContentHTML(html);                
        this.popup.updateSize();
        
        if(pixel){
	        var popupPos = pixel.clone();
	
	        var relPos = this.popup.relativePosition;
	         
	        var relPosX = relPos.charAt(1);
	        var relPosY = relPos.charAt(0);
	
	        var offsetX = 0;
	        var offsetY = 0;
	        
	        if (relPosX == 'l') {
	            offsetX -= 10;
	        } else 
	        if (relPosX == 'r') {
	            offsetX += 10;
	        }        
	        if (relPosY == 't') {
	            offsetY -= 10;
	        } else 
	        if (relPosY == 'b') {
	            offsetY += 10;
	        }
	        
	        this.popup.anchor.offset = new OpenLayers.Pixel(offsetX,offsetY);
	        this.popup.lonlat = this.control.map.getLonLatFromPixel(popupPos);                
        }
        this.popup.show();        
        
	},

    CLASS_NAME: "OpenLayers.Handler.PointFromRef"
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */


/**
 * @requires OpenLayers/Handler/Point.js
 * @requires OpenLayers/Geometry/Point.js
 * @requires OpenLayers/Geometry/LineString.js
 */

/**
 * Class: OpenLayers.Handler.Path
 * Handler to draw a path on the map.  Path is displayed on mouse down,
 * moves on mouse move, and is finished on mouse up.
 *
 * Inherits from:
 *  - <OpenLayers.Handler.Point>
 */
OpenLayers.Handler.ConstrainedPath = OpenLayers.Class(OpenLayers.Handler.Point, {
    
    /**
     * Property: line
     * {<OpenLayers.Feature.Vector>}
     */
    line: null,
    
    /**
     * Property: ring
     * {Boolean} Set the line as closed ring. Default false
     */
    ring: false,
       
    /**
     * Property: infoOnMouse
     * {Boolean} Set the line information as length and angle on a mouse popup. 
     * Default true.
     */
    infoOnMouse: false,
    
    /**
     * Property: relativeAngle
     * {Boolean} Set angles as relative to previous side and not to Horizontal.
     * Default true.
     */
    relativeAngle: true,
        
    /*
     * Costante da non cambiare.
     */
    N_COINCIDING_FIRST_POINT: 2,    
    
    /**
     * Method: activate
     * Activate event observation for the keyboard
     * Returns:
     * {Boolean} true if ok.
     */
    activate: function(){
    	if(OpenLayers.Handler.Point.prototype.activate.apply(this, arguments)) {
    		OpenLayers.Event.observe(document, "keydown", this.eventListener);
            return true;
        }else{
        	return false;
        }
    },
    
    /**
     * Method: deactivate
     * Remove event observation for the keyboard
     * Returns:
     * {Boolean} true if ok.
     */
    deactivate: function() {
    	var deactivated = false;
        if (OpenLayers.Handler.Point.prototype.deactivate.apply(this, arguments)) {
            OpenLayers.Event.stopObserving(document, "keydown", this.eventListener);            
            deactivated = true;
        }
        return deactivated;        
    },
    
    /**
     * Method: setRelativeAngle
     * Set the angle as relative to the previous side. If the
     * parameter is false the angle is relative to horizontal
     * 
     * Parameters:
     * isRelative - {Boolean} 
     */
    setRelativeAngle: function(isRelative){
    	if(isRelative){
    		this.relativeAngle = true;
    	}else{
    		this.relativeAngle = false;
    	}
    },
    
    /**
     * Method: runCommand
     * Check if the command is relative to the previous point
     * and set the next point.
     * 
     * Parameters:
     * command - {String} CAD command
     */
    runCommand: function (command){    	
    	var isRelative = command.charAt(0) == '@'; 
    	if(isRelative){
    		command = command.substring(1);
    	}
    	//if((!command || command=="CH") && this.ring && this.line.geometry.components.length >= (this.N_COINCIDING_FIRST_POINT + 2)){    		
    	if((!command || command=="END")){
    		this.dblclick();
    	}else{
    		this.setNextPoint(command, isRelative);
    	}
    },
    
    setNextPoint: function (command, isRelative){
    	    	    	
    	// modulo ed angolo
    	if(command.indexOf('<') != -1){
    		
    		var modulo_angolo = command.split("<");    		    	
    		this.setNextMA(modulo_angolo[0],modulo_angolo[1]);    		
    		
    	// x e y
    	}else if (command.indexOf(',') != -1){
    		
    		var x_y = command.split(",");
    		this.setNextXY(x_y[0],x_y[1]);    		    		
    		    		
		// solo modulo    		
    	}else{
    		if(!isNaN(command)){
    			this.setNextMA(command,null); 
    		}
    	}
    	/*
    	if(this.drawing){
    		this.modifyFeature(); 
    		this.drawFeature();
    	}
    	this.callback("distance", [this.distance]);
    	*/
    },
    
    setNextMA: function (modulo,angolo){
    	
    	var m = null;
    	var a = null;
    			
		if(modulo){
			if(!isNaN(modulo)){
				m = modulo;
			}    				
		}
		if(angolo){
			if(!isNaN(angolo)){
				a = angolo;
			}    				
		}
		
		this.setConstraint(true,m,a);
    },
    
    setNextXY: function (dx,dy){
    	var x = null;
    	var y = null;
    			
		if(dx){
			if(!isNaN(dx)){
				x = dx;
			}    				
		}
		if(dy){
			if(!isNaN(dy)){
				y = dy;
			}    				
		}
		
		this.setConstraint(false,x,y);
    	
    },
    
    clearConstraint : function(){
    	this.constraint = null;
    },
    
    setConstraint : function(isPolar,firstCoord,secondCoord){
    	this.constraint = {x:null,y:null,modulo:null,angolo:null};
    	this.constraint.isPolar = isPolar;
    	if(isPolar){
    		this.constraint.modulo = firstCoord;
    		this.constraint.angolo = secondCoord;    		    	
    	}else{
    		this.constraint.x = firstCoord;
    		this.constraint.y = secondCoord;    		
    	}
    	
    	// se entrambe i vincoli sono impostati il punto � definito e quindi lo si inserisce
    	if( (this.constraint.modulo && this.constraint.angolo) || (this.constraint.x && this.constraint.y) ){
    			this.updatePoint();
    			//var g = this.point.geometry.clone();
    			var p = new OpenLayers.Pixel(this.point.geometry.x,this.point.geometry.y);
    			var evt = {xy:p};
    			this.mousedown(evt);
    			this.mouseup(evt);
    			/*
    			this.addPoint(p);
    			*/
    			this.clearConstraint();
    	} 
    },
    
	createInfoPopup: function(lonlat){
		if(this.popup){
			this.destroyInfoPopup();
		}
		this.popup = new OpenLayers.Popup.Anchored("infoOnMouse",lonlat,new OpenLayers.Size(100,30),"",{size : new OpenLayers.Size(0,0), offset : new OpenLayers.Pixel(0,0)});
        this.popup.setOpacity(0.6);
        this.popup.setBorder("solid black 1px");        
        this.control.map.addPopup(this.popup);
        this.popup.hide(); 
	},
	
	destroyInfoPopup: function(){
		this.control.map.removePopup(this.popup);
		this.popup.destroy();
		this.popup = null;
	},
	
	updateInfoPopup: function(pixel,distance,angoloRAD){
		
		this.popup.hide();      
		var gradiS = angoloRAD*180/Math.PI;
		var gradi = Math.floor(gradiS);
		var primi = Math.round((gradiS - gradi)*60);
		
		var html  = "<div>Distanza = " + Math.round(distance*100)/100;
		    html += "<br />";
		    html += "Angolo = " + gradi + "<sup>o</sup>" + primi + "<sup>'</sup></div>";
        this.popup.setContentHTML(html);                
        this.popup.updateSize();
        
        var popupPos = pixel.clone();

        var relPos = this.popup.relativePosition;
         
        var relPosX = relPos.charAt(1);
        var relPosY = relPos.charAt(0);

        var offsetX = 0;
        var offsetY = 0;
        
        if (relPosX == 'l') {
            offsetX -= 10;
        } else 
        if (relPosX == 'r') {
            offsetX += 10;
        }        
        if (relPosY == 't') {
            offsetY -= 10;
        } else 
        if (relPosY == 'b') {
            offsetY += 10;
        }
        
        this.popup.anchor.offset = new OpenLayers.Pixel(offsetX,offsetY);
        this.popup.lonlat = this.control.map.getLonLatFromPixel(popupPos);                
        this.popup.show();        
        
	},
	
	updatePoint: function(){
		
		var nPoints = this.line.geometry.components.length;
        var lastPoint = this.line.geometry.components[this.line.geometry.components.length-this.N_COINCIDING_FIRST_POINT];
        
		if(this.constraint != null){
        	if(this.constraint.isPolar){
        		        		
        		if(this.constraint.angolo){
        			
        			var rad = this.constraint.angolo * Math.PI / 180;
        			
        			var d = (this.constraint.modulo)?this.constraint.modulo:this.point.geometry.distanceTo(lastPoint);
        			        			
        			// angolo rispetto all'orizzontale
	        		if(nPoints == this.N_COINCIDING_FIRST_POINT){	        			
	        			this.point.geometry.x = lastPoint.x + ( d * Math.cos(rad));
	        			this.point.geometry.y = lastPoint.y + ( d * Math.sin(rad));
	        		// angolo rispetto a quello del lato precedente	
	        		}else if (nPoints > this.N_COINCIDING_FIRST_POINT){
	        			if(this.relativeAngle){
		        			var dx = lastPoint.x - this.line.geometry.components[this.line.geometry.components.length-(this.N_COINCIDING_FIRST_POINT+1)].x; 
		        			var dy = lastPoint.y - this.line.geometry.components[this.line.geometry.components.length-(this.N_COINCIDING_FIRST_POINT+1)].y;
		        			var a = Math.atan2(dy,dx);
		        			rad += a;
	        			}
	        			this.point.geometry.x = lastPoint.x + ( d * Math.cos(rad));
	        			this.point.geometry.y = lastPoint.y + ( d * Math.sin(rad));
	        		}
	        	// Il modulo � stato messo in else per evitare problemi nel caso in cui il punto sia nella stessa posizione del precedente.
        		}else if(this.constraint.modulo){
        			var scale = this.constraint.modulo/this.point.geometry.distanceTo(lastPoint);        			
    				this.point.geometry.resize(scale,this.line.geometry.components[this.line.geometry.components.length-this.N_COINCIDING_FIRST_POINT]);
        		}
        		
        		        		
        	}else{
        		if (nPoints >= this.N_COINCIDING_FIRST_POINT){
	        		if(this.constraint.x){	  		
	        			this.point.geometry.x = lastPoint.x + Number(this.constraint.x);
	        		}
	        		if(this.constraint.y){
	        			this.point.geometry.y = lastPoint.y + Number(this.constraint.y);
	        		}
        		}
        	}
        }
	},
	
	fromAbsoluteToRelativeAngle: function(rad){
		var nPoints = this.line.geometry.components.length;
        var lastPoint = this.line.geometry.components[this.line.geometry.components.length-this.N_COINCIDING_FIRST_POINT];	
		if (nPoints > this.N_COINCIDING_FIRST_POINT){
			var dx = lastPoint.x - this.line.geometry.components[this.line.geometry.components.length-(this.N_COINCIDING_FIRST_POINT+1)].x; 
			var dy = lastPoint.y - this.line.geometry.components[this.line.geometry.components.length-(this.N_COINCIDING_FIRST_POINT+1)].y;
			var a = Math.atan2(dy,dx);
			rad -= a;
		}
		return rad;
	},
	
	/**
	 * Method: clearFirstPoint
     * Remove first point of the path.
     * Is usefull if first poi is used as reference point
	 */
	clearFirstPoint: function(){
		this.clearFirstOrLastPoint(true);
	},
	
	/**
	 * Method: clearFirstPoint
     * Remove first point of the path.
     * Is usefull if first poi is used as reference point
	 */
	clearLastPoint: function(){
		this.clearFirstOrLastPoint(false);
	},
	
	clearFirstOrLastPoint: function(first){
		if(this.line){
			if(this.line.geometry.components.length > this.N_COINCIDING_FIRST_POINT){
				this.line.geometry.removeComponent(this.line.geometry.getVertices()[first?0:this.line.geometry.getVertices().length-2]);
				this.drawFeature();
			}
		}
	},
	
    /**
     * Constructor: OpenLayers.Handler.Path
     * Create a new path hander
     *
     * Parameters:
     * control - {<OpenLayers.Control>} The control that owns this handler
     * callbacks - {Object} An object with a properties whose values are
     *     functions.  Various callbacks described below.
     * options - {Object} An optional object with properties to be set on the
     *           handler
     *
     * Named callbacks:
     * create - Called when a sketch is first created.  Callback called with
     *     the creation point geometry and sketch feature.
     * modify - Called with each move of a vertex with the vertex (point)
     *     geometry and the sketch feature.
     * point - Called as each point is added.  Receives the new point geometry.
     * done - Called when the point drawing is finished.  The callback will
     *     recieve a single argument, the linestring geometry.
     * cancel - Called when the handler is deactivated while drawing.  The
     *     cancel callback will receive a geometry.
     */
    initialize: function(control, callbacks, options) {    	
        OpenLayers.Handler.Point.prototype.initialize.apply(this, arguments);
        // cache the bound event listener method so it can be unobserved later
        this.eventListener = OpenLayers.Function.bindAsEventListener(
            this.keydown, this
        );
    },
        
    /**
     * Method: createFeature
     * Add temporary geometries
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
     *     feature.
     */
    createFeature: function(pixel) {
        var lonlat = this.control.map.getLonLatFromPixel(pixel);
        this.point = new OpenLayers.Feature.Vector(
            new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
        );
        this.line = new OpenLayers.Feature.Vector(
            new OpenLayers.Geometry.LineString([this.point.geometry])
        );
        
        if(this.infoOnMouse){
        	this.createInfoPopup(lonlat);
        }        
        this.callback("create", [this.point.geometry, this.getSketch()]);
        this.point.geometry.clearBounds();
        this.layer.addFeatures([this.line, this.point], {silent: true});
//        this.setConstraint(true,null,-90);
    },
        
    /**
     * Method: destroyFeature
     * Destroy temporary geometries
     */
    destroyFeature: function() {
        OpenLayers.Handler.Point.prototype.destroyFeature.apply(this);
        this.line = null;
        this.drawing = false;
        if(this.popup){
        	this.destroyInfoPopup();
        }          
    },

    /**
     * Method: removePoint
     * Destroy the temporary point.
     */
    removePoint: function() {
        if(this.point) {
            this.layer.removeFeatures([this.point]);
        }
    },
    
    /**
     * Method: addPoint
     * Add point to geometry.  Send the point index to override
     * the behavior of LinearRing that disregards adding duplicate points.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The pixel location for the new point.
     */
    addPoint: function(pixel) {
        this.layer.removeFeatures([this.point]);
        var lonlat = this.control.map.getLonLatFromPixel(pixel);
        this.point = new OpenLayers.Feature.Vector(
            new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
        );
        this.line.geometry.addComponent(
            this.point.geometry, this.line.geometry.components.length
        );
        
        if(this.line.geometry.components.length == this.N_COINCIDING_FIRST_POINT){
        	this.callback("firstPoint", [this.point.geometry, this.getGeometry()]);        	        	
        }
        this.callback("point", [this.point.geometry, this.getGeometry()]);
        this.callback("modify", [this.point.geometry, this.getSketch()]);
        this.clearConstraint();
        this.drawFeature();
        this.callback("aftermodify", [this.point.geometry, this.getSketch()]);
    },
    
    /**
     * Method: freehandMode
     * Determine whether to behave in freehand mode or not.
     *
     * Returns:
     * {Boolean}
     */
     /*
    freehandMode: function(evt) {
        return (this.freehandToggle && evt[this.freehandToggle]) ?
                    !this.freehand : this.freehand;
    },
    * */

    /**
     * Method: modifyFeature
     * Modify the existing geometry given the new point
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The updated pixel location for the latest
     *     point.
     */
    modifyFeature: function(pixel) {
    	if(!this.point){
    		this.createFeature(pixel);
    	}
    	
        var lonlat = this.control.map.getLonLatFromPixel(pixel);
        this.point.geometry.x = lonlat.lon;
        this.point.geometry.y = lonlat.lat;
        
        var nPoints = this.line.geometry.components.length;
        
        var lastPoint = this.line.geometry.components[this.line.geometry.components.length-this.N_COINCIDING_FIRST_POINT];
        this.updatePoint();
        
        this.callback("modify", [this.point.geometry, this.getSketch()]);
        
        if(this.point.geometry && lastPoint){
	        var distance = this.point.geometry.distanceTo(lastPoint);
	        if(this.infoOnMouse){        	
	        	var angolo = 0;
	        	if(this.constraint && this.constraint.angolo){
	        		angolo = this.constraint.angolo*Math.PI/180;
	        	}else{
	        		var dx = this.point.geometry.x - lastPoint.x; 
		        	var dy = this.point.geometry.y - lastPoint.y;
		        	var a = Math.atan2(dy,dx);
		        	angolo = a;
	        	}
	        	this.updateInfoPopup(pixel,this.point.geometry.distanceTo(lastPoint),this.relativeAngle?this.fromAbsoluteToRelativeAngle(angolo):angolo);
	        }
	        this.callback("distance", [distance]);
        }        
        
        this.point.geometry.clearBounds();
        this.drawFeature();
        this.callback("aftermodify", [this.point.geometry, this.getSketch()]);
    },

    /**
     * Method: drawFeature
     * Render geometries on the temporary layer.
     */
    drawFeature: function() {
        this.layer.drawFeature(this.line, this.style);
        this.layer.drawFeature(this.point, this.style);        
        //this.layer.drawFeature(new OpenLayers.Feature.Vector(this.line.geometry.components[this.line.geometry.components.length-this.N_COINCIDING_FIRST_POINT]), this.style);
    },

    /**
     * Method: getSketch
     * Return the sketch feature.
     *
     * Returns:
     * {<OpenLayers.Feature.Vector>}
     */
    getSketch: function() {
        return this.line;
    },
    
    /*
    geometryClone: function() {
        //return this.line.geometry.components[this.line.geometry.components.length-this.N_COINCIDING_FIRST_POINT].clone();
        return this.point.geometry.clone();
    },
    */

    /**
     * Method: getGeometry
     * Return the sketch geometry.  If <multi> is true, this will return
     *     a multi-part geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.LineString>}
     */
    getGeometry: function() {
        var geometry = this.line && this.line.geometry;
        if(geometry && this.multi) {
            geometry = new OpenLayers.Geometry.MultiLineString([geometry]);
        }
        return geometry;
    },
    
    drawFirstPoint: function(lon,lat){
    	if(this.lastDown)
    		return;
    	var pixel = this.control.map.getPixelFromLonLat(new OpenLayers.LonLat(lon,lat));
    	var evt = {xy:pixel};
    	this.mousedown(evt);
    	this.mouseup(evt);
    	this.mousemove(evt);
    },
    
    undo: function(){
    	if(this.drawing){
    		if(this.constraint){
    			this.clearConstraint();
    		}else if(this.line.geometry.components.length > this.N_COINCIDING_FIRST_POINT){
    			this.clearLastPoint();
    		}else if(this.line.geometry.components.length <= this.N_COINCIDING_FIRST_POINT){
    			this.removePoint();
    			this.cancel();
    		}
    	}    	
    },

    /**
     * Method: mousedown
     * Handle mouse down.  Add a new point to the geometry and
     * render it. Return determines whether to propagate the event on the map.
     * 
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns: 
     * {Boolean} Allow event propagation
     */
    mousedown: function(evt) {
        // ignore double-clicks    	
    	
        if (this.lastDown && this.lastDown.equals(evt.xy)) {
            return false;
        }
        if(this.lastDown == null) {
            if(this.persist) {
                this.destroyFeature();
            }
            //this.createFeature(evt.xy);
        } else if((this.lastUp == null) || !this.lastUp.equals(evt.xy)) {
            this.addPoint(evt.xy);
        }
        this.mouseDown = true;
        this.lastDown = evt.xy;
        this.drawing = true;
        return false;
    },

    /**
     * Method: mousemove
     * Handle mouse move.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     * 
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns: 
     * {Boolean} Allow event propagation
     */
    mousemove: function (evt) {
       // if(this.drawing) { 
            //if(this.mouseDown && this.freehandMode(evt)) {
            //    this.addPoint(evt.xy);
            //} else {
                this.modifyFeature(evt.xy);
            //}
       // }
        return true;
    },
    
    /**
     * Method: mouseup
     * Handle mouse up.  Send the latest point in the geometry to
     * the control. Return determines whether to propagate the event on the map.
     * 
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns: 
     * {Boolean} Allow event propagation
     */
    mouseup: function (evt) {
        this.mouseDown = false;
        if(this.drawing) {
            //if(this.freehandMode(evt)) {
             //   this.removePoint();
            //    this.finalize();
           // } else {
                if(this.lastUp == null) {
                   this.addPoint(evt.xy);
                }
                this.lastUp = evt.xy;
            //}
            return false;
        }
        return true;
    },
  
    /**
     * Method: dblclick 
     * Handle double-clicks.  Finish the geometry and send it back
     * to the control.
     * 
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns: 
     * {Boolean} Allow event propagation
     */
    dblclick: function(evt) {

        var index = this.line.geometry.components.length - 1;
        this.line.geometry.removeComponent(this.line.geometry.components[index]);
        if(this.ring){
        	this.line = new OpenLayers.Feature.Vector(
	          new OpenLayers.Geometry.LinearRing(this.line.geometry.getVertices())
	        );
	        this.layer.addFeatures([this.line], {silent: true});
	        this.drawFeature();
        }
        this.removePoint();
        this.finalize();

        return false;
    },
    
    keydown: function(evt){
    	if(evt.keyCode == 46 /* Canc */ || (evt.ctrlKey && evt.keyCode == 90) /* Ctrl + z */){
    		this.undo();
    		return false;	
    	} else if (evt.ctrlKey && evt.keyCode == 13) {
    		this.dblclick();
    		return false;
    	}    	
    	return true;
    },

    CLASS_NAME: "OpenLayers.Handler.ConstrainedPath"
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */


/**
 * @requires OpenLayers/Handler/Path.js
 * @requires OpenLayers/Geometry/Polygon.js
 */

/**
 * Class: OpenLayers.Handler.Polygon
 * Handler to draw a polygon on the map.  Polygon is displayed on mouse down,
 * moves on mouse move, and is finished on mouse up.
 *
 * Inherits from:
 *  - <OpenLayers.Handler.Path>
 *  - <OpenLayers.Handler>
 */
OpenLayers.Handler.ConstrainedPoint = OpenLayers.Class(OpenLayers.Handler.ConstrainedPath, {	
	
	/**
     * Constructor: OpenLayers.Handler.ConstrainedPoint
     * Create a Constrained Point Handler.
     *
     * Parameters:
     * control - {<OpenLayers.Control>} The control that owns this handler
     * callbacks - {Object} An object with a properties whose values are
     *     functions.  Various callbacks described below.
     * options - {Object} An optional object with properties to be set on the
     *           handler
     *
     * Named callbacks:
     * firstPoint - Called when the first point is first created.  Callback called with
     *     the creation point geometry.
     * distance - Called with each move of a vertex with the distance from the last point.
     */
    initialize: function(control, callbacks, options) {
        OpenLayers.Handler.ConstrainedPath.prototype.initialize.apply(this, arguments);
        this.ring = false;
    },
	
    /**
     * Method: getGeometry
     *
     * Returns:
     * {<OpenLayers.Geometry.Polygon>}
     */		
    getGeometry: function() {  
    	var geometry = this.line && this.line.geometry;
    	if(geometry){
        	geometry = this.line.geometry.components[this.line.geometry.components.length-1];
    	}
    	return geometry;
    },
   

    CLASS_NAME: "OpenLayers.Handler.ConstrainedPoint"
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */


/**
 * @requires OpenLayers/Handler/Path.js
 * @requires OpenLayers/Geometry/Polygon.js
 */

/**
 * Class: OpenLayers.Handler.Polygon
 * Handler to draw a polygon on the map.  Polygon is displayed on mouse down,
 * moves on mouse move, and is finished on mouse up.
 *
 * Inherits from:
 *  - <OpenLayers.Handler.Path>
 *  - <OpenLayers.Handler>
 */
OpenLayers.Handler.ConstrainedPolygon = OpenLayers.Class(OpenLayers.Handler.ConstrainedPath, {
    
    /**
     * Parameter: polygon
     * {<OpenLayers.Feature.Vector>}
     */
    polygon: null,
    
    N_COINCIDING_FIRST_POINT: 3,

    /**
     * Constructor: OpenLayers.Handler.ConstrainedPolygon
     * Create a Polygon Handler.
     *
     * Parameters:
     * control - {<OpenLayers.Control>} The control that owns this handler
     * callbacks - {Object} An object with a properties whose values are
     *     functions.  Various callbacks described below.
     * options - {Object} An optional object with properties to be set on the
     *           handler
     *
     * Named callbacks:
     * create - Called when a sketch is first created.  Callback called with
     *     the creation point geometry and sketch feature.
     * modify - Called with each move of a vertex with the vertex (point)
     *     geometry and the sketch feature.
     * point - Called as each point is added.  Receives the new point geometry.
     * done - Called when the point drawing is finished.  The callback will
     *     recieve a single argument, the polygon geometry.
     * cancel - Called when the handler is deactivated while drawing.  The
     *     cancel callback will receive a geometry.
     */
    initialize: function(control, callbacks, options) {
        OpenLayers.Handler.ConstrainedPath.prototype.initialize.apply(this, arguments);
        this.ring = true;
    },
    
    /**
     * Method: createFeature
     * Add temporary geometries
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
     *     feature.
     */
    createFeature: function(pixel) {
        var lonlat = this.control.map.getLonLatFromPixel(pixel);
        this.point = new OpenLayers.Feature.Vector(
            new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
        );
        var lr = new OpenLayers.Geometry.LinearRing([this.point.geometry]);
        
        // Sovrascrivo il removeComponent per poter eliminare anche i punti
        // che il LinearRing non permette
        lr.removeComponent = function(point) {
	        if (this.components.length > 3) {
	
	            //remove last point
	            this.components.pop();
	            
	            //remove our point
	            OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, 
	                                                                    arguments);
	            //append copy of first point
	            var firstPoint = this.components[0];
	            OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, 
	                                                                [firstPoint]);
	        }
    	}; 
        this.line = new OpenLayers.Feature.Vector(
          lr 
        );
        this.polygon = new OpenLayers.Feature.Vector(
            new OpenLayers.Geometry.Polygon([this.line.geometry])
        );
        if(this.infoOnMouse){
        	this.createInfoPopup(lonlat);
        }
        this.callback("create", [this.point.geometry, this.getSketch()]);
        this.point.geometry.clearBounds();
        this.layer.addFeatures([this.polygon, this.point], {silent: true});
    },

    /**
     * Method: destroyFeature
     * Destroy temporary geometries
     */
    destroyFeature: function() {
        OpenLayers.Handler.ConstrainedPath.prototype.destroyFeature.apply(this);
        this.polygon = null;
    },

    /**
     * Method: drawFeature
     * Render geometries on the temporary layer.
     */
    drawFeature: function() {
        this.layer.drawFeature(this.polygon, this.style);
        this.layer.drawFeature(this.point, this.style);
    },
    
    /**
     * Method: getSketch
     * Return the sketch feature.
     *
     * Returns:
     * {<OpenLayers.Feature.Vector>}
     */
    getSketch: function() {
        return this.polygon;
    },

    /**
     * Method: getGeometry
     * Return the sketch geometry.  If <multi> is true, this will return
     *     a multi-part geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.Polygon>}
     */
    getGeometry: function() {
        var geometry = this.polygon && this.polygon.geometry;
        if(geometry && this.multi) {
            geometry = new OpenLayers.Geometry.MultiPolygon([geometry]);
        }
        return geometry;
    },

    /**
     * Method: dblclick
     * Handle double-clicks.  Finish the geometry and send it back
     * to the control.
     * 
     * Parameters:
     * evt - {Event} 
     */
    dblclick: function(evt) {
        //if(!this.freehandMode(evt)) {
            // remove the penultimate point
            var index = this.line.geometry.components.length - 2;
            this.line.geometry.removeComponent(this.line.geometry.components[index]);
            this.removePoint();
            this.finalize();
        //}
        return false;
    },

    CLASS_NAME: "OpenLayers.Handler.ConstrainedPolygon"
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @requires OpenLayers/Control.js
 */

/**
 * Class: OpenLayers.Control.Attribution
 * Controllo che aggiunge in mappa le attribuzioni gestendo la possibilità che un singolo layer openlayers 
 * visualizzi più di un layer con diversa attribuzione, caso possibile quando vengono raggruppate le richieste alla stesso wms
 * Utilizza la prorietà 'attribution' di ogni layer, che può essere anche un array.
 *
 * Inherits from:
 *  - <OpenLayers.Control>
 */
OpenLayers.Control.AttributionMulti = 
  OpenLayers.Class(OpenLayers.Control, {
    
	  
  /**
     * APIProperty: separator
     * {String} String used to separate layers.
     */
    separator: ", ",
    
    /**
     * APIProperty: template
     * {String} Template for the attribution. This has to include the substring
     *     "${layers}", which will be replaced by the layer specific
     *     attributions, separated by <separator>. The default is "${layers}".
     */
    template: "${layers}",
    
    /**
     * Constructor: OpenLayers.Control.Attribution 
     * 
     * Parameters:
     * options - {Object} Options for control.
     */
	  
    
    /**
     * Constructor: OpenLayers.Control.AttributionMulti 
     * 
     * Parameters:
     * options - {Object} Options for control.
     */
	  
    /** 
     * Method: destroy
     * Destroy control.
     */
    destroy: function() {
        this.map.events.un({
            "removelayer": this.updateAttribution,
            "addlayer": this.updateAttribution,
            "changelayer": this.updateAttribution,
            "changebaselayer": this.updateAttribution,
            scope: this
        });
        
        OpenLayers.Control.prototype.destroy.apply(this, arguments);
    },    
    
    /**
     * Method: draw
     * Initialize control.
     * 
     * Returns: 
     * {DOMElement} A reference to the DIV DOMElement containing the control
     */    
    draw: function() {
        OpenLayers.Control.prototype.draw.apply(this, arguments);
        
        this.map.events.on({
            'changebaselayer': this.updateAttribution,
            'changelayer': this.updateAttribution,
            'addlayer': this.updateAttribution,
            'removelayer': this.updateAttribution,
            scope: this
        });
        this.updateAttribution();
        
        return this.div;    
    },

	  /**
     * Method: updateAttribution
     * Aggiorna l'attribuzione
     */
    updateAttribution: function() {
    	 
        var attributions = [];
        if (this.map && this.map.layers) {
            for(var i=0, len=this.map.layers.length; i<len; i++) {
                var layer = this.map.layers[i];
                if (layer.attribution && layer.getVisibility()) {
                	// controlla se ci sono più attribuzioni per questo layer
                	if (layer.attribution.constructor === Array) {
                		for (var j=0; j<layer.attribution.length; j++) {
                			var buff = "";
                			if (typeof layer.attribution[j] === 'string') {
                				buff = layer.attribution[j];	
                        	} else {
                        		buff = layer.attribution[j].title;
                        	}
	                		// add attribution only if attribution text is unique
	                        if (OpenLayers.Util.indexOf(
	                                        attributions, buff) === -1) {
	                            attributions.push( buff );
	                        }
                		}
                	} else {
                		// add attribution only if attribution text is unique
                		var buff = "";
            			if (typeof layer.attribution === 'string') {
            				buff = layer.attribution;
                    	} else {
                    		buff = layer.attribution.title;
                    	}
                        if (OpenLayers.Util.indexOf(
                                        attributions, buff) === -1) {
                        	attributions.push(buff);
                        }	
                	}
                }
            } 
            this.div.innerHTML = OpenLayers.String.format(this.template, {
                layers: attributions.join(this.separator)
            });
        }
    },

    CLASS_NAME: "OpenLayers.Control.AttributionMulti"
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/*
 * Fix OpenLayers IE
 */
if(document.namespaces == null){document.createElement('namespaces');}

/*
 * Fix vari non contenuto nella public release
 */
Ext.namespace("TolomeoExt");

//Corregge il fatto che la window "ruba" il focus di un eventuale campo di una form .Per esempio in windowToponomastica
/*Ext.override(Ext.Window, {
    toFront : function(e){
        if(this.manager.bringToFront(this)){
            if(e && !e.getTarget().focus){
                this.focus();
            }
        }
        return this;
    }
});
*/

/**
 * @method applyIfEmpty
 * Fix per diverso comportamento applyIf tra 3.0 e 3.1
 * 
 * Parameters:
 * o - .
 * c - .
 */	
TolomeoExt.applyIfEmpty = function (o,c) {
	if(o){
        for(var p in c){
        	//o["aaa"] = 'ale';
        	//o["TOLOMEOServer"] = c["TOLOMEOServer"];
        	
        	if (Ext.isEmpty(o[p])) {
                o[p] = c[p];
            //    alert(c[p]);
            }
        }
    }
}


if(Ext.isIE8) {
	Ext.form.ComboBox.prototype.shadow = false;
    Ext.Panel.prototype.shadow = false;
    Ext.menu.Menu.prototype.shadow = false;
    Ext.ToolTip.prototype.floating.shadow = false;
    Ext.ToolTip.prototype.floating.shim = true;
    Ext.ToolTip.prototype.floating.useDisplay = true;
    Ext.ToolTip.prototype.floating.constrain = false;
}

/*
 * Ovveride per connessioni SSL
 */
if(Ext.isSecure) {
	Ext.BLANK_IMAGE_URL= "https://pratomaps.comune.prato.it/img/pixel.gif";
	Ext.chart.Chart.CHART_URL = "/js/images/blankfile";
	Ext.FlashComponent.EXPRESS_INSTALL_URL = "/js/images/blankfile"
	Ext.SSL_SECURE_URL='javascript:false';
}else{
	Ext.BLANK_IMAGE_URL= "http://pratomaps.comune.prato.it/img/pixel.gif";
}


OpenLayers.DOTS_PER_INCH = 25.4 / 0.28;

/*
 * Cambio la risoluzione in base al sistema operativo
 */
/*
if(Ext.isWindows) {
	OpenLayers.DOTS_PER_INCH = 96;
} else if (Ext.isMac) {
	OpenLayers.DOTS_PER_INCH = 72;
} else if (Ext.isLinux) {
	OpenLayers.DOTS_PER_INCH = 72;
}
*/


/**
 * Sostituisce un parametro di una url con un altro
 * 
 * @param url - url nella quale viene effettuata la sostituzione
 * @param paramname - nome del parametro
 * @param paramvalue - nuovo valore del parametro
 * 
 */

TolomeoExt.urlAddOrChangeParameter = function (url, paramname, paramvalue) {

	var inizio = 0;
	var pre = "";
	var post = "";
	
	if (url.indexOf(paramname+"=")!=-1) {
		pre = url.substring(0,url.indexOf(paramname+"="));
		inizio = url.indexOf(paramname+"=");
		if (url.indexOf("&",inizio)!=-1) {
			var fine = url.indexOf("&",inizio);
			post = url.substring(fine); 
		} 
	} else {
		pre = url;
	}
	
	return pre + paramname+'=' + paramvalue + post;
	
}


/**
 * @method loadScript
 * Copyright (C) 2006-2007 Dao Gottwald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact information:
 *   Dao Gottwald  <dao@design-noir.de>
 *
 * version  1.6
 * url      http://design-noir.de/webdev/JS/loadScript/
 */
function loadScript(url, callback) {
	var f = arguments.callee;
	if (!("queue" in f))
		f.queue = {};
	var queue =  f.queue;
	if (url in queue) { // script is already in the document
		if (callback) {
			if (queue[url]) // still loading
				queue[url].push(callback);
			else // loaded
				callback();
		}
		return;
	}
	queue[url] = callback ? [callback] : [];
	var script = document.createElement("script");
	script.type = "text/javascript";
	script.onload = script.onreadystatechange = function() {
		if (script.readyState && script.readyState != "loaded" && script.readyState != "complete")
			return;
		script.onreadystatechange = script.onload = null;
		while (queue[url].length)
			queue[url].shift()();
		queue[url] = null;
	};
	script.src = url;
	document.getElementsByTagName("head")[0].appendChild(script);
}
/* Esempio di utilizzo
 * 
   <html>
	<head>
		<title>Test</title>
	</head>
	<body>
		<script type="text/javacript" src="scriptloader.js"></script>
		<script type="text/javascript">
			alert("Start");

			loadScript("otherscript.js",function() {
				// Call something in other script
				DoOther();
			});

			alert("Stop");
		</script>
	</body>
  </html>
 * 
 * 
 * 
 * 
 * 
 * 
 */ 

// FIX del fatto che IE<=8 non implementa la funzione standard degli array indexOf
if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(obj, start) {
	     for (var i = (start || 0), j = this.length; i < j; i++) {
	         if (this[i] === obj) { return i; }
	     }
	     return -1;
	}
}

// Production steps of ECMA-262, Edition 6, 22.1.2.1
if (!Array.from) {
  Array.from = (function () {
    var toStr = Object.prototype.toString;
    var isCallable = function (fn) {
      return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
    };
    var toInteger = function (value) {
      var number = Number(value);
      if (isNaN(number)) { return 0; }
      if (number === 0 || !isFinite(number)) { return number; }
      return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
    };
    var maxSafeInteger = Math.pow(2, 53) - 1;
    var toLength = function (value) {
      var len = toInteger(value);
      return Math.min(Math.max(len, 0), maxSafeInteger);
    };

    // The length property of the from method is 1.
    return function from(arrayLike/*, mapFn, thisArg */) {
      // 1. Let C be the this value.
      var C = this;

      // 2. Let items be ToObject(arrayLike).
      var items = Object(arrayLike);

      // 3. ReturnIfAbrupt(items).
      if (arrayLike == null) {
        throw new TypeError('Array.from requires an array-like object - not null or undefined');
      }

      // 4. If mapfn is undefined, then let mapping be false.
      var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
      var T;
      if (typeof mapFn !== 'undefined') {
        // 5. else
        // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
        if (!isCallable(mapFn)) {
          throw new TypeError('Array.from: when provided, the second argument must be a function');
        }

        // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
        if (arguments.length > 2) {
          T = arguments[2];
        }
      }

      // 10. Let lenValue be Get(items, "length").
      // 11. Let len be ToLength(lenValue).
      var len = toLength(items.length);

      // 13. If IsConstructor(C) is true, then
      // 13. a. Let A be the result of calling the [[Construct]] internal method 
      // of C with an argument list containing the single item len.
      // 14. a. Else, Let A be ArrayCreate(len).
      var A = isCallable(C) ? Object(new C(len)) : new Array(len);

      // 16. Let k be 0.
      var k = 0;
      // 17. Repeat, while k < len... (also steps a - h)
      var kValue;
      while (k < len) {
        kValue = items[k];
        if (mapFn) {
          A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
        } else {
          A[k] = kValue;
        }
        k += 1;
      }
      // 18. Let putStatus be Put(A, "length", len, true).
      A.length = len;
      // 20. Return A.
      return A;
    };
  }());
}


// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.com/#x15.4.4.19
if (!Array.prototype.map) {
	
  Array.prototype.map = function(callback, thisArg) {

    var T, A, k;

    if (this == null) {
      throw new TypeError(" this is null or not defined");
    }

    // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
    // 3. Let len be ToUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If IsCallable(callback) is false, throw a TypeError exception.
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== "function") {
      throw new TypeError(callback + " is not a function");
    }

    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
    if (thisArg) {
      T = thisArg;
    }

    // 6. Let A be a new array created as if by the expression new Array(len) where Array is
    // the standard built-in constructor with that name and len is the value of len.
    A = new Array(len);

    // 7. Let k be 0
    k = 0;

    // 8. Repeat, while k < len
    while(k < len) {

      var kValue, mappedValue;

      // a. Let Pk be ToString(k).
      //   This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
      //   This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
        kValue = O[ k ];

        // ii. Let mappedValue be the result of calling the Call internal method of callback
        // with T as the this value and argument list containing kValue, k, and O.
        mappedValue = callback.call(T, kValue, k, O);

        // iii. Call the DefineOwnProperty internal method of A with arguments
        // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
        // and false.

        // In browsers that support Object.defineProperty, use the following:
        // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });

        // For best browser support, use the following:
        A[ k ] = mappedValue;
      }
      // d. Increase k by 1.
      k++;
    }

    // 9. return A
    return A;
  };      
}


if (!Array.prototype.reduce) {
	
  Array.prototype.reduce = function(callback /*, initialValue*/) {
  	
      if (this === null) {
        throw new TypeError( 'Array.prototype.reduce ' + 
          'called on null or undefined' );
      }
      if (typeof callback !== 'function') {
        throw new TypeError( callback +
          ' is not a function');
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0; 

      // Steps 3, 4, 5, 6, 7      
      var k = 0; 
      var value;

      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++; 
        }

        // 3. If len is 0 and initialValue is not present,
        //    throw a TypeError exception.
        if (k >= len) {
          throw new TypeError( 'Reduce of empty array ' +
            'with no initial value' );
        }
        value = o[k++];
      }

      // 8. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kPresent be ? HasProperty(O, Pk).
        // c. If kPresent is true, then
        //    i.  Let kValue be ? Get(O, Pk).
        //    ii. Let accumulator be ? Call(
        //          callbackfn, undefined,
        //          « accumulator, kValue, k, O »).
        if (k in o) {
          value = callback(value, o[k], k, o);
        }

        // d. Increase k by 1.      
        k++;
      }

      // 9. Return accumulator.
      return value;
    }
}

// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {

  Array.prototype.forEach = function(callback/*, thisArg*/) {

    var T, k;

    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    // 1. Let O be the result of calling toObject() passing the
    // |this| value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get() internal
    // method of O with the argument "length".
    // 3. Let len be toUint32(lenValue).
    var len = O.length >>> 0;

    // 4. If isCallable(callback) is false, throw a TypeError exception. 
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }

    // 5. If thisArg was supplied, let T be thisArg; else let
    // T be undefined.
    if (arguments.length > 1) {
      T = arguments[1];
    }

    // 6. Let k be 0
    k = 0;

    // 7. Repeat, while k < len
    while (k < len) {

      var kValue;

      // a. Let Pk be ToString(k).
      //    This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty
      //    internal method of O with argument Pk.
      //    This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal
        // method of O with argument Pk.
        kValue = O[k];

        // ii. Call the Call internal method of callback with T as
        // the this value and argument list containing kValue, k, and O.
        callback.call(T, kValue, k, O);
      }
      // d. Increase k by 1.
      k++;
    }
    // 8. return undefined
  };
}

// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
  Object.keys = (function () {
    'use strict';
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
        dontEnums = [
          'toString',
          'toLocaleString',
          'valueOf',
          'hasOwnProperty',
          'isPrototypeOf',
          'propertyIsEnumerable',
          'constructor'
        ],
        dontEnumsLength = dontEnums.length;

    return function (obj) {
      if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
        throw new TypeError('Object.keys called on non-object');
      }

      var result = [], prop, i;

      for (prop in obj) {
        if (hasOwnProperty.call(obj, prop)) {
          result.push(prop);
        }
      }

      if (hasDontEnumBug) {
        for (i = 0; i < dontEnumsLength; i++) {
          if (hasOwnProperty.call(obj, dontEnums[i])) {
            result.push(dontEnums[i]);
          }
        }
      }
      return result;
    };
  }());
}

if (!window.JSON) {
  window.JSON = {
    parse: function(sJSON) { return eval('(' + sJSON + ')'); },
    stringify: (function () {
      var toString = Object.prototype.toString;
      var isArray = Array.isArray || function (a) { return toString.call(a) === '[object Array]'; };
      var escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'};
      var escFunc = function (m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); };
      var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g;
      return function stringify(value) {
        if (value == null) {
          return 'null';
        } else if (typeof value === 'number') {
          return isFinite(value) ? value.toString() : 'null';
        } else if (typeof value === 'boolean') {
          return value.toString();
        } else if (typeof value === 'object') {
          if (typeof value.toJSON === 'function') {
            return stringify(value.toJSON());
          } else if (isArray(value)) {
            var res = '[';
            for (var i = 0; i < value.length; i++)
              res += (i ? ', ' : '') + stringify(value[i]);
            return res + ']';
          } else if (toString.call(value) === '[object Object]') {
            var tmp = [];
            for (var k in value) {
              if (value.hasOwnProperty(k))
                tmp.push(stringify(k) + ': ' + stringify(value[k]));
            }
            return '{' + tmp.join(', ') + '}';
          }
        }
        return '"' + value.toString().replace(escRE, escFunc) + '"';
      };
    })()
  };
}

if(!String.format){
	String.format = function(format) {
	    var args = Array.prototype.slice.call(arguments, 1);
	    return format.replace(/{(\d+)}/g, function(match, number) { 
	      return typeof args[number] != 'undefined'
	        ? args[number] 
	        : match
	      ;
	    });
	};
}/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.namespace("TolomeoExt.Vars");
	
/**
 * Function: TolomeoExt.Vars.ApplyIfDefaults
 *
 * Parameters:
 * obj - {} obj
 */
TolomeoExt.Vars.ApplyIfDefaults = function(obj) {
	
	// passando alla versione 3.1 di ext la applyIf agisce se le proprieta' non sono definite, mentre prima lo faceva anche se erano null
	// per questo ho combiato con il codice esplicito sotto riportato 
	TolomeoExt.applyIfEmpty(obj,
					{ TOLOMEOServer: 		 TolomeoExt.Vars.TOLOMEOServer,
					  TOLOMEOContext: 		 TolomeoExt.Vars.TOLOMEOContext,
					  TOLOMEOStaticRoot: 	 TolomeoExt.Vars.TOLOMEOStaticRoot,
					  TOLOMEOServerSettings: TolomeoExt.Vars.TOLOMEOServerSettings,
					  paramsJS: TolomeoExt.Vars.paramsJS
					});
	/*var o = obj;
	var c = { TOLOMEOServer: TolomeoExt.Vars.TOLOMEOServer,
			  TOLOMEOContext: TolomeoExt.Vars.TOLOMEOContext,
			  paramsJS: TolomeoExt.Vars.paramsJS
			};
					
    if(o){
        for(var p in c){
        	//o["aaa"] = 'ale';
        	//o["TOLOMEOServer"] = c["TOLOMEOServer"];
        	
        	if (Ext.isEmpty(o[p])) {
                o[p] = c[p];
            //    alert(c[p]);
            }
        }
    }*/					
}

Ext.define('TolomeoExt.ToloI18n', {
	extend: 'Ext.util.Observable', 
	requires: [
        'Ext.app.Application'        
	],

	//@private
	defaultLanguage: 'it',

	constructor: function(config){
		config = config || {};
		this.loaded = false;

		var me = this;
		this.language = me.formatLanguageCode(config.lang || me.guessLanguage());
		
		this.addEvents('loaded');
		
		this.callParent(arguments);
	},
	
	setLanguage: function(lang){
		this.language = lang;
		this.fireEvent('languageChanged', lang);
	},
	
	getLanguage: function(){
		return this.language;
	
	},
	
	load: function(){
		// Applico in questo momento e non nel costruttore perchè questo oggetto viene creato subito, 
		// quindi prima che i valori corretti siano disponibili
		
		if(this.isLoaded()) return;
				
		var self = this;
		
		if(!(TolomeoExt.Vars && TolomeoExt.Vars.ApplyIfDefaults && TolomeoExt.Vars.TOLOMEOServer)) {
			setTimeout(function(){self.load.call(self)},500);
			return;
		}
		
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		var url =  this.TOLOMEOServer + this.TOLOMEOStaticRoot + '/js/ext/extJS/locale/ext-lang-'+ this.language + '.js';
		
		Ext.Loader.loadScript({
            url: url,
            onLoad: this.loadPart2,
            onError: this.onFailure,
            scope: this
        });
	}, 
	
	loadPart2: function(){
		
		var url = this.TOLOMEOServer + this.TOLOMEOContext + "/AjaxI18nServlet";
		new TolomeoExt.ToloCrossAjax().request({
			method: 'get',
			url: url,
			params: {
				lang: this.language,
				format: 'ext'
			},
			success: this.loadSuccess,
			failure: function(transport){
				var errText = transport.responseText ? transport.responseText : ""+transport;
				alert(errText);
				/*this.fireEvent('selectRequestEnd',{
					ok:false,
					nResults:0,
					errText:transport.responseText?transport.responseText:""+transport
				});
				this.showAjaxError(transport);*/
			}, 
			scope: this
		});
		
	},
	
	loadSuccess: function(results, store) {
		
		var mf = new MessageFormat(this.language);
		
		this.i18n = mf.compile(results[0].raw);
		this.loaded = true;
    			
		this.fireEvent('loaded');
	},
	
    onFailure: function() {
        Ext.Msg.alert('Failure', 'Failed to load locale file.');
    },
	
	isLoaded: function(){
		return this.loaded;
	},
	
    getMsg: function(key, varobj) {
		if(this.i18n) {
			if (this.i18n[key]) {
				return this.i18n[key](varobj);
			}else{
				//alert("Translation of string with key '"+key+"' not found");
				return "NoTranslation. Key "+ key + " not found!";
			}
			
		} else {
			//alert("Translation of string with key '"+key+"' not found");
			return "NoTranslation. Translations not loaded!";
		}
	},

	/**
	 * @private
	 */
	guessLanguage: function(){
		return (navigator.language || navigator.browserLanguage || navigator.userLanguage || this.defaultLanguage);
	}, 
	
	/**
	 * @private
	 */
	formatLanguageCode: function(lang){
		var langCodes = lang.split('-'),
            primary, second;
		primary = (langCodes[0]) ? langCodes[0].toLowerCase() : '';
		second = (langCodes[1]) ? langCodes[1].toUpperCase() : '';

        return langCodes.length > 1 ? [primary, second].join('-') : primary;
	}

});

// Definisco subito la variabile globale, perchè sia disponibile in fase di caricamento degli altri js
// Il caricamento dei file della lingua avviene prima dell'avvio dell'applicazione (su onBeforeLaunch) e solo quando finito l'applicazione viene avviata
ToloI18n = Ext.create('TolomeoExt.ToloI18n',{
					lang: Ext.Object.fromQueryString(window.location.search).lang || 'it'
			});

// Ritardo il lancio di Ext.onReady di 120 secondi per essere strasicuro che non venga lanciato fino a che tutto non è pronto
// ATTENZIONE !!! Impostata anche sulla jsp che fa il caricamento dinamico degli script, per essere sicuri che tutto funzioni anche in eventuali casi misti di dynamic loader + Ext.onReady			
Ext.EventManager.deferReadyEvent = 120000;  

// Registro sul loaded del ToloI18n di controllare se, una volta che la lingua è caricata, il documento sarebbe già pronto per il lancio dell'Ext.onReady oppure no.
// Se lo è lancio immediatamente il metodo Ext.EventManager.fireReadyEvent che è quello che viene di fatto lanciato da Ext e quando arriverà anche il lancio differito non farà nulla
// di nuovo, perché la lista degli registrazioni all'evento è stata già esaurita (se si teme possa fare qualcosa, una volta lanciato si può sovrascrivere il metodo fireReadyEvent in modo che non faccia niente).
// Se invece il documento non è pronto (Ext.isReady = false) si rimette il deferReadyEvent ad 1 che è il valore di default e la sequenza degli eventi farà il suo normale corso.
ToloI18n.on('loaded', 
	function() {
		if(Ext.isReady){
			Ext.EventManager.fireReadyEvent();
		} else {
			Ext.EventManager.deferReadyEvent = 1;			
		}
	},
	this,
	{single: true}
)

    
ToloI18n.load();			
			



/*
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110�1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo � un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo � un software libero; � possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo � distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILIT� o
 IDONEIT� PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110�1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/
/**
 * overview Definizione costanti e tipi geometrici utilizzati dal progetto Tolomeo <br/>
 * <br/>
 * name Tolomeo - Geometrie
 * @author Ing. Alessandro Radaelli <br/>Comune di Prato
 * 
* Costante che rappresenta il tipo di geometria: Punto 
* @type number
*/
var geomTypePoint   = 1;
/**
* Costante che rappresenta il tipo di geometria: Linea 
* @type number
*/
var geomTypeLine    = 2;
/**
* Costante che rappresenta il tipo di geometria: Poligono 
* @type number
*/
var geomTypePolygon = 3;
/**
* Costante che rappresenta il tipo di geometria: Cerchio 
* @type number
*/
var geomTypeCircle  = 4;


/**
 * @class TolomeoExt.Point
 * Rappresentazione di un punto
 * 
 * @constructor
 * 
 * 
 * @param {Number} x
 * coordinata x
 * 
 * @param {Number} y
 * coordinata y
 * 
 */
 function Point(x, y) {
 	/**
 	 * @property {Number} x
 	 * coordinata x
 	 * 
 	 */
 	this.x = x;
 	/**
 	 * @property {Number} y
 	 * coordinata y
 	 * 
 	 */
 	this.y = y; 	
 }
 
/**
 * @method clone
 * Restituisce un nuovo punto con le medesime coordinate del punto stesso 
 * 
 * @return {TolomeoExt.Point}
 * 
 * 
 */
 Point.prototype.clone = function() {
        return new Point(this.x ,this.y);
 }
 
/**
 * @method transform
 * Trasforma il punto dal sistema di riferimento iniziale a quello di destinazione
 * 
 * @param {String} source
 * codice EPSG del sistema di riferimento di partenza (Es. EPSG:26591) 
 * 
 * @param {String} dest
 * codice EPSG del sistema di riferimento di destinazione (Es. EPSG:4326)
 * 
 */
 Point.prototype.transform = function(source, dest) {
    var newPoint = TolomeoExt.Projection.transform(this, source, dest);
    this.x = newPoint.x;
    this.y = newPoint.y;
 }
 
/**
 * @method round
 * Arrotonda le coordinate con un certo numero di decimali
 * 
 * @param {Number} precision
 * numero di decimali 
 * 
 */
 Point.prototype.round = function(precision){
 	var factor = Math.pow(10,Math.round(precision) || 0);
 	this.x = Math.round(this.x * factor)/factor;
 	this.y = Math.round(this.y * factor)/factor;
 }   
    
/**
 * @method toString
 * 
 * 
 * @return {String}
 * 
 * 
 */
 Point.prototype.toString = function() {
    return (this.x + "," + this.y);
 }
 
 /**
  * @method Point.parseWkt
  * Restituisce un oggetto Point dalla relativa geometria in formato wkt
  * 
  * @parma {String} wktPoint 
  * punto in formato WKT
  * 
  */
 Point.parseWkt = function(wktPoint) {
	if(!Point.isWktPoint(wktPoint)) return null;
	var xy = wktPoint.split("(")[1].split(")")[0].split(" ");
	return new Point(xy[0], xy[1]);
 }
 

 /**
  * @method Point.isWktPoint
  * Restituisce true se la stringa passata è un punto in formato wkt
  * 
  * @parma {String} wktPoint 
  * punto in formato WKT
  * 
  */
 Point.isWktPoint = function(wktPoint) {
	 if(wktPoint === undefined || typeof(wktPoint) !== "string" || wktPoint === "") return false;
	 
	 if (wktPoint.indexOf("POINT")!=-1) return true
		else return false;
 }
 
/**
 * @class TolomeoExt.BBox
 * Rappresentazione di un bounding box
 * 
 * @constructor
 * 
 * 
 * @param {Number} left
 * coordinata x minima
 * 
 * @param {Number} bottom
 * coordinata y minima
 * 
 * @param {Number} right
 * coordinata x massima
 * 
 * @param {Number} top
 * coordinata y massima
 * 
 */
 function BBox(left,bottom,right,top){
 	/**
   * @property {Number} left
   * coordinata x minima
   * 
 	 */
 	this.left   = left;
 	/**
   * @property {Number} bottom
   * coordinata y minima
   * 
 	 */
 	this.bottom = bottom;
 	/**
   * @property {Number} right
   * coordinata x massima
   * 
 	 */
 	this.right  = right;
 	/**
   * @property {Number} top
   * coordinata y massima
   * 
 	 */
 	this.top    = top
 }
 
/**
 * @method create
 * 
 * 
 * @param {TolomeoExt.BBox} bbox
 * 
 * 
 * @return {TolomeoExt.BBox}
 * 
 * 
 */
 BBox.create = function(bbox){
 	return new BBox(bbox.left,bbox.bottom,bbox.right,bbox.top);
 }
 
/**
 * @method transform
 * Trasforma il bounding box dal sistema di riferimento iniziale a quello di destinazione
 * 
 * @param {String} source
 * codice EPSG del sistema di riferimento di partenza (Es. EPSG:26591) 
 * 
 * @param {String} dest
 * codice EPSG del sistema di riferimento di destinazione (Es. EPSG:4326)
 * 
 */
 BBox.prototype.transform = function(source, dest) {
 	
 	var leftBottomPoint = new Point(this.left , this.bottom);
	var rightTopPoint   = new Point(this.right, this.top);
										
	leftBottomPoint = TolomeoExt.Projection.transform(leftBottomPoint,source,dest);
	rightTopPoint   = TolomeoExt.Projection.transform(rightTopPoint,  source,dest);
		    
    this.left   = leftBottomPoint.x;
    this.bottom = leftBottomPoint.y;
    this.right  = rightTopPoint.x;
    this.top    = rightTopPoint.y;
 }
 
/**
 * @method format
 * 
 * 
 * @param {String} separator
 * 
 * 
 * @return {String}
 * 
 * 
 */
 BBox.prototype.format = function(separator) {
 	separator = separator || " ";
    return (this.left + separator + this.bottom + separator + this.right + separator + this.top);
 }
 
/**
 * @method toString
 * 
 * 
 * @return {String}
 * 
 * 
 */
 BBox.prototype.toString = function() {
    return this.format(" ");
 }
 
/**
 * @class TolomeoExt.JSGeometryArray
 * Array di geometrie. E' composto da <br>
 * <ul>
 *  	<li>geometries - array contenente elementi di tipo JSGeometry </li>
 * 		<li>boundingbox - la stringa WKT che rappresenta il rettangolo minimo che contiene l'insieme delle geometrie</li>
 * </ul>
 * Questo costruttore crea un JSGeometryArray a partire dalla stringa JSON 
 * see JSGeometry
 * 
 * @constructor
 * 
 * 
 * @param {String} JSONString
 * String JSON dalla quale costruire l'oggetto
 * 
 */
function JSGeometryArray(JSONString) {
	var ret = new Array();
	if (arguments.length!=0) {	
		var buff1 = eval('(' + JSONString + ')');
		/**
		 * @type TolomeoExt.JSGeometry
		 */
		var buff = buff1.geometries;
		this.boundingbox = buff1.boundingbox;
		for (var i=0;i<buff.length;i++) {
			ret[i] = new JSGeometry(buff[i].codTPN, buff[i].key, buff[i].description, buff[i].geometry, buff[i].boundingbox, buff[i].SRID, buff[i].getFeatureInfoLink,
									buff[i].attributes, buff[i].sourceHTTP, buff[i].sourceBBOX, buff[i].sourceLayer,buff[i].sourceStyle,
									buff[i].sourceWidth, buff[i].sourceHeight, buff[i].sourceX, buff[i].sourceY);
		}
	}
	this.geometries = ret;
	
}

/**
 * @method FromUntypedArray
 * Inizializza a partire da un JSGeometryArray non tipizzato (hanno le giuste propriet� ma non i prototype)
 * tipicamente perche' l'array stesso proviene da JSON
 * 
 * @param {Array} JSGeometryArray
 * non tipizzato da trasformare
 * 
 */
JSGeometryArray.prototype.FromUntypedArray = function (untypedJSGeometryArray) {
	
	var untypedArray = untypedJSGeometryArray.geometries;
	for (var i=0;i<untypedArray.length; i++) {
		var geom = new JSGeometry(untypedArray[i].codTPN, 
									  untypedArray[i].key,
									  untypedArray[i].description.replace(/\"/g,'\\"'),
									  untypedArray[i].geometry,
									  untypedArray[i].boundingbox, 
									  untypedArray[i].SRID,
									  untypedArray[i].getFeatureInfoLink,
									  untypedArray[i].attributes,
									  untypedArray[i].sourceHTTP,
									  untypedArray[i].sourceBBOX,
									  untypedArray[i].sourceLayer,
									  untypedArray[i].sourceStyle,
									  untypedArray[i].sourceWidth,
									  untypedArray[i].sourceHeight,
									  untypedArray[i].sourceX,
									  untypedArray[i].sourceY
		);
	    this.geometries[i]= geom;
	}
	this.boundingbox = untypedJSGeometryArray.boundingbox;
		
}

/**
 * @method FromStore
 * 
 * 
 * @param {Array} results
 * 
 * 
 * @param {Object} store
 * 
 * 
 * @return {Object}
 * 
 * 
 */
JSGeometryArray.prototype.FromStore = function (results, store) {
	
	var untypedArray = new Object();
	untypedArray.geometries = new Array(); 
	for (var i=0; i<results.length; i++) {
		var geom = results[i].data;
		untypedArray.geometries.push(geom);
	}
	if (store.reader) {
		//EtJS 3
		untypedArray.boundingbox = store.reader.meta.boundingbox;
	} else {
		//EtJS 4
		untypedArray.boundingbox = store.getProxy().getReader().metaData.boundingbox;
	}
	
	return this.FromUntypedArray(untypedArray);
}

/**
 * @method FromStoreSingleRecord
 * 
 * 
 * @param {Object} result
 * 
 * 
 * @return {Object}
 * 
 * 
 */
JSGeometryArray.prototype.FromStoreSingleRecord = function (result) {
	
	var untypedArray = new Object();
	untypedArray.geometries = new Array();
	untypedArray.geometries.push(result);
	untypedArray.boundingbox = result.boundingbox;
	untypedArray.getFeatureInfoLink = result.getFeatureInfoLink;
	
	return this.FromUntypedArray(untypedArray);
	
}

/**
 * @method add
 * Aggiunge un oggetto JSGeometry alle geometrie di JSGeometryArray<br/>
 * Accetta in ingresso sia stringhe JSON contententi l'oggetto JSGeometry sia oggetti JSGeometry
 * 
 * @param {TolomeoExt.JSGeometry} jsGeometry
 * 
 * 
 */
JSGeometryArray.prototype.add = function(jsGeometry){
	var newGeom;
	
	if (jsGeometry instanceof String) {
		newGeom = new JSGeometry(jsGeometry);
		this.geometries.push(newGeom);
	} else {
		if (jsGeometry instanceof JSGeometry) {
			this.geometries.push(jsGeometry);
		} else {
			if (jsGeometry instanceof JSGeometryArray) {
				for (var i=0; i<jsGeometry.geometries.length; i++){
					this.geometries.push(jsGeometry.geometries[i]);
				}
			}	
		}
	}
	
}

/**
 * @method toString
 * 
 * 
 * @return {String}
 * La stringa JSOn che rappresenta l'oggetto
 * 
 */
JSGeometryArray.prototype.toString = function () {
	var ret = "{ boundingbox: \"" + this.boundingbox + "\",";
	
	ret += "geometries: [";
	for (var i=0;i<this.geometries.length;i++) {
		if (i!=0) ret += ",";
		ret  += this.geometries[i].toString();
	}
	ret += "]}";
	return ret;
}

/**
 * @method size
 * 
 * 
 * @return {Number}
 * Il numero di elementi dell'array
 * 
 */
JSGeometryArray.prototype.size = function(){
	if(!this.geometries){
		return 0;
	}
	return this.geometries.length;
}

/**
 * @method clear
 * 
 * 
 * @param {Number} codTPN
 * 
 * 
 */
JSGeometryArray.prototype.clear = function(codTPN){
	var removedGeoms = [];
	if(this.geometries){		
		if (codTPN) {			
			var buff=new Array();
			for (var i=0;i<this.geometries.length;i++) {
				if (this.geometries[i].codTPN==codTPN) {
					buff.push(i);
				}	
			}		
			for (var i=0; i<buff.length;i++) {
				removedGeoms.push(this.geometries.splice(buff.pop(),1));
			}
		} else {
			for (var i=0; i<this.geometries.length;i++){
				removedGeoms[i] = this.geometries[i]; 
			}
			this.geometries.length=0;
			//this.geometries.clear();
		}
		return removedGeoms;
	}
}

/**
 * @method getByIndex
 * 
 * 
 * @param {Number} index
 * 
 * 
 * @return {TolomeoExt.JSGeometry}
 * 
 * 
 */
JSGeometryArray.prototype.getByIndex = function(index){
	if (index<0 || index>=this.size()) return null;	
	return this.geometries[index];
}

/**
 * @method getByCodTPN
 * Ritorna la/le geometrie contenute ed appartenenti al layer identificato dal codTN passato.
 * Ritorna null se non presenti
 * 
 * @param {Number} codTPN
 * 
 * 
 * @return {TolomeoExt.JSGeometry}
 * 
 * 
 */
JSGeometryArray.prototype.getByCodTPN = function(codTPN){
	var ret = null;
	for (var i=0;i<this.geometries.length;i++) {
		if (this.geometries[i].codTPN==codTPN) {
			if (ret==null) ret = new JSGeometryArray();
			ret.add(this.geometries[i]);
		}	
	}
	return ret;
}

/**
 * @method ContainsCodTPN
 * Ritorna true se contiene una o pi� geometrie appartenenti al layer identificato dal codTN passato.
 * altrimenti ritorna false
 * 
 * @param {Number} codTPN
 * 
 * 
 * @return {Boolean}
 * 
 * 
 */
JSGeometryArray.prototype.ContainsCodTPN = function(codTPN){
	
	for (var i=0;i<this.geometries.length;i++) {
		if (this.geometries[i].codTPN==codTPN) return true;
	}
	
	return false;
}
	
/**
 * @class TolomeoExt.JSGeometry
 * Rappresenta una geometria complessa. 
 * 
 * @constructor
 * Il costruttore se viene passato un solo parametro costruisce l'oggetto interpretando quanto passato come una stringa JSON, altrimenti utilizzando i valori passati
 * 
 * @param {Number} codTPN
 * Se è l'unico valore passato deve essere la stringa JSON che rappresenta l'oggetto da creare, altrimenti e' il valore da assegnare alla property omonima
 * 
 * @param {String} key
 * e' il valore da assegnare alla property omonima
 * 
 * @param {String} description
 * e' il valore da assegnare alla property omonima
 * 
 * @param {String} geometry
 * e' il valore da assegnare alla property omonima
 * 
 * @param {String} boundingbox
 * e' il valore da assegnare alla property omonima
 * 
 * @param {String} SRID
 * e' l'ID del sistema di riferimento utilizzato per la geometria (es. EPSG:26591)
 * 
 * @param {String} getFeatureInfoLink
 * e' il link per ottenere la getfeatureinfo in un WMS
 * 
 * @param {String} attributi
 * attributi della feature
 * 
 * @param {String} sourceHTTP 
 * url server nel caso feature prelevata da wms
 * 
 * @param {String} sourceBBOX 
 * BBOX utilizzato per la getfeatureinfo nel caso feature prelevata da wms
 * 
 * @param {String} sourceLayer 
 * Layer utilizzato per la getfeatureinfo nel caso feature prelevata da wms
 * 
 * @param {String} sourceStyle 
 * Style utilizzato per la getfeatureinfo nel caso feature prelevata da wms
 * 
 * 
 * @param {String} sourceWidth 
 * Width utilizzato per la getfeatureinfo nel caso feature prelevata da wms
 * 
 * @param {String} sourceHeight 
 * Height utilizzato per la getfeatureinfo nel caso feature prelevata da wms
 * 
 * @param {String} sourceX 
 * X utilizzato per la getfeatureinfo nel caso feature prelevata da wms
 * 
 * @param {String} sourceY 
 * Y utilizzato per la getfeatureinfo nel caso feature prelevata da wms
 * 
 */
function JSGeometry(codTPN, key, description, geometry, boundingbox, SRID, getFeatureInfoLink,
					attributes, sourceHTTP, sourceBBOX, sourceLayer, sourceStyle,
					sourceWidth, sourceHeight, sourceX, sourceY) {
	if (arguments.length == 1) {
		var JSONString = codTPN;
		var buff = eval('(' + JSONString + ')');
	
	/**
     * @property {Number} codTPN
     * Codice del layer di appartenenza dell'oggetto 
     * 
     */
		this.geometryIsValid = true;
		
		/**
     * @property {Number} codTPN
     * Codice del layer di appartenenza dell'oggetto 
     * 
     */
		this.codTPN = buff.codTPN;
		/**
     * @property {String} key
     * Chiave unica identificativa dell'oggetto all'interno del layer
     * 
     */
		this.key = buff.key;
		/**
     * @property {String} description
     * Descrizione dell'oggetto da utilizzarsi quando e' necessario per l'utente distiguere un oggetto dall'altro
     * 
     */
		this.description = buff.description;
		/**
     * @property {String} geometry
     * Rappresentazione WKT della geometria
     * 
     */
		this.geometry = buff.geometry;	
		/**
     * @property {String} boundingbox
     * Rappresentazione WKT del minimo rettangolo che contiene la geometria
     * 
     */
		this.boundingbox = buff.boundingbox;
		this.SRID = buff.SRID;
		this.getFeatureInfoLink = buff.getFeatureInfoLink;
		this.attributes = buff.attributes;
		this.sourceHTTP = buff.sourceHTTP;
		this.sourceBBOX = buff.sourceBBOX;
		this.sourceLayer = buff.sourceLayer;
		this.sourceStyle = buff.sourceStyle;
		
		this.sourceWidth = buff.sourceWidth;
		this.sourceHeight = buff.sourceHeight;
		this.sourceX = buff.sourceX;
		this.sourceY = buff.sourceY;
		
	} else {
		this.codTPN = codTPN;
		this.key = key;
		this.description = description;
		this.geometry = geometry;
		this.boundingbox = boundingbox;
		this.SRID = SRID;
		this.getFeatureInfoLink = getFeatureInfoLink;
		this.attributes = attributes;
		this.sourceHTTP = sourceHTTP;
		this.sourceBBOX = sourceBBOX;
		this.sourceLayer = sourceLayer;
		this.sourceStyle = sourceStyle;
		
		this.sourceWidth = sourceWidth;
		this.sourceHeight = sourceHeight;
		this.sourceX = sourceX;
		this.sourceY = sourceY;
	}
	
} 

/**
 * @method isPoint
 * 
 * 
 * @return {Boolean}
 * 
 * 
 */
JSGeometry.prototype.isPoint= function () {
	if (this.geometry.indexOf("POINT")!=-1) return true
	else return false;
}

/**
 * @method toString
 * 
 * 
 * @return {String}
 * La stringa JSOn che rappresenta l'oggetto
 * 
 */
JSGeometry.prototype.toString= function () {
		var retVal = "{codTPN: " + this.codTPN;
		retVal += ", key: \"" + this.key + "\"";
		retVal += ", description: \"" + this.description + "\"";
		retVal += ", geometry: \"" + this.geometry + "\"";
		retVal += ", SRID: \"" + this.SRID + "\"";//}";
		retVal += ", attributes: " + Ext.JSON.encode(this.attributes) + "";
		retVal += ", sourceHTTP: \"" + this.sourceHTTP + "\""; 
		retVal += ", sourceBBOX: \"" + this.sourceBBOX + "\""; 
		retVal += ", sourceLayer: \"" + this.sourceLayer + "\""; 
		retVal += ", sourceStyle: \"" + this.sourceStyle + "\"";
		retVal += ", sourceWidth: \"" + this.sourceWidth + "\"";
		retVal += ", sourceHeight: \"" + this.sourceHeight + "\"";
		retVal += ", sourceX: \"" + this.sourceX + "\"";
		retVal += ", sourceY: \"" + this.sourceY + "\"";
		
		retVal += ", getFeatureInfoLink: \"" + this.getFeatureInfoLink + "\"}"; 
		return retVal;
	}

/**
 * @method getParts
 * 
 * 
 * @return {JSGeometryArray}
 * Se multipart insieme delle geometrie che compongono la geometria, altrimenti la geometria stessa
 * 
 */
JSGeometry.prototype.getParts= function () {
	
	if (!this.parts) {
		var wktParts = TolomeoExt.ToloViewerOLPanel.getWKTParts(this.geometry);
		this.parts = new JSGeometryArray();
		if (wktParts) {
			for (var i=0; i < wktParts.length; i++){
				
				//codTPN, key, description, geometry, boundingbox, SRID, getFeatureInfoLink
				var g = new JSGeometry(
					this.codTPN,  this.key, "Parte " + (i+1), wktParts[i], "", this.SRID );
				this.parts.add(g);
			}
		}
	}
	return this.parts;
	
}// Il ; in testa al codice è stato messo perché la minificazione e concatenazione interpretava questo codice come il lancio di na funzione definita nel file che lo precede
;(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.MessageFormat = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var reserved = require('reserved-words');
var parse = require('messageformat-parser').parse;


/** Creates a new message compiler. Called internally from {@link MessageFormat#compile}.
 *
 * @class
 * @param {MessageFormat} mf - A MessageFormat instance
 * @property {object} locales - The locale identifiers that are used by the compiled functions
 * @property {object} runtime - Names of the core runtime functions that are used by the compiled functions
 * @property {object} formatters - The formatter functions that are used by the compiled functions 
 */
function Compiler(mf) {
    this.mf = mf;
    this.lc = null;
    this.locales = {};
    this.runtime = {};
    this.formatters = {};
}

module.exports = Compiler;


/** Utility function for quoting an Object's key value iff required
 *
 *  Quotes the key if it contains invalid characters or is an
 *  ECMAScript 3rd Edition reserved word (for IE8).
 */
Compiler.propname = function(key, obj) {
  if (/^[A-Z_$][0-9A-Z_$]*$/i.test(key) &&
     ['break', 'continue', 'delete', 'else', 'for', 'function', 'if', 'in', 'new',
      'return', 'this', 'typeof', 'var', 'void', 'while', 'with', 'case', 'catch',
      'default', 'do', 'finally', 'instanceof', 'switch', 'throw', 'try'].indexOf(key) < 0) {
    return obj ? obj + '.' + key : key;
  } else {
    var jkey = JSON.stringify(key);
    return obj ? obj + '[' + jkey + ']' : jkey;
  }
}


/** Utility function for escaping a function name iff required
 */
Compiler.funcname = function(key) {
  var fn = key.trim().replace(/\W+/g, '_');
  return reserved.check(fn, 'es2015', true) || /^\d/.test(fn) ? '_' + fn : fn;
}


/** Utility formatter function for enforcing Bidi Structured Text by using UCC
 *
 *  List inlined from data extracted from CLDR v27 & v28
 *  To verify/recreate, use the following:
 *
 *     git clone https://github.com/unicode-cldr/cldr-misc-full.git
 *     cd cldr-misc-full/main/
 *     grep characterOrder -r . | tr '"/' '\t' | cut -f2,6 | grep -C4 right-to-left
 */
Compiler.bidiMarkText = function(text, locale) {
  function isLocaleRTL(locale) {
    var rtlLanguages = ['ar', 'ckb', 'fa', 'he', 'ks($|[^bfh])', 'lrc', 'mzn',
                        'pa-Arab', 'ps', 'ug', 'ur', 'uz-Arab', 'yi'];
    return new RegExp('^' + rtlLanguages.join('|^')).test(locale);
  }
  var mark = JSON.stringify(isLocaleRTL(locale) ? '\u200F' : '\u200E');
  return mark + ' + ' + text + ' + ' + mark;
}


/** @private */
Compiler.prototype.cases = function(token, plural) {
  var needOther = true;
  var r = token.cases.map(function(c) {
    if (c.key === 'other') needOther = false;
    var s = c.tokens.map(function(tok) { return this.token(tok, plural); }, this);
    return Compiler.propname(c.key) + ': ' + (s.join(' + ') || '""');
  }, this);
  if (needOther) throw new Error("No 'other' form found in " + JSON.stringify(token));
  return '{ ' + r.join(', ') + ' }';
}


/** @private */
Compiler.prototype.token = function(token, plural) {
  if (typeof token == 'string') return JSON.stringify(token);

  var fn, args = [ Compiler.propname(token.arg, 'd') ];
  switch (token.type) {
    case 'argument':
      return this.mf.bidiSupport ? Compiler.bidiMarkText(args[0], this.lc) : args[0];

    case 'select':
      fn = 'select';
      args.push(this.cases(token, this.mf.strictNumberSign ? null : plural));
      this.runtime.select = true;
      break;

    case 'selectordinal':
      fn = 'plural';
      args.push(0, Compiler.funcname(this.lc), this.cases(token, token), 1);
      this.locales[this.lc] = true;
      this.runtime.plural = true;
      break;

    case 'plural':
      fn = 'plural';
      args.push(token.offset || 0, Compiler.funcname(this.lc), this.cases(token, token));
      this.locales[this.lc] = true;
      this.runtime.plural = true;
      break;

    case 'function':
      if (this.mf.intlSupport && !(token.key in this.mf.fmt) && (token.key in this.mf.constructor.formatters)) {
        var fmt = this.mf.constructor.formatters[token.key];
        this.mf.fmt[token.key] = (typeof fmt(this.mf) == 'function') ? fmt(this.mf) : fmt;
      }
      if (!this.mf.fmt[token.key]) throw new Error('Formatting function ' + JSON.stringify(token.key) + ' not found!');
      args.push(JSON.stringify(this.lc));
      if (token.params) switch (token.params.length) {
          case 0:   break;
          case 1:   args.push(JSON.stringify(token.params[0])); break;
          default:  args.push(JSON.stringify(token.params)); break;
      }
      fn = Compiler.propname(token.key, 'fmt');
      this.formatters[token.key] = true;
      break;

    case 'octothorpe':
      if (!plural) return '"#"';
      fn = 'number';
      args = [ Compiler.propname(plural.arg, 'd'), JSON.stringify(plural.arg) ];
      if (plural.offset) args.push(plural.offset);
      this.runtime.number = true;
      break;
  }

  if (!fn) throw new Error('Parser error for token ' + JSON.stringify(token));
  return fn + '(' + args.join(', ') + ')';
};


/** Recursively compile a string or a tree of strings to JavaScript function sources
 *
 *  If `src` is an object with a key that is also present in `plurals`, the key
 *  in question will be used as the locale identifier for its value. To disable
 *  the compile-time checks for plural & selectordinal keys while maintaining
 *  multi-locale support, use falsy values in `plurals`.
 *
 * @param {string|object} src - the source for which the JS code should be generated
 * @param {string} lc - the default locale
 * @param {object} plurals - a map of pluralization keys for all available locales
 */
Compiler.prototype.compile = function(src, lc, plurals) {
  if (typeof src != 'object') {
    this.lc = lc;
    var pc = plurals[lc] || { cardinal: [], ordinal: [] };
    var r = parse(src, pc).map(function(token) { return this.token(token); }, this);
    return 'function(d) { return ' + (r.join(' + ') || '""') + '; }';
  } else {
    var result = {};
    for (var key in src) {
      var lcKey = plurals.hasOwnProperty(key) ? key : lc;
      result[key] = this.compile(src[key], lcKey, plurals);
    }
    return result;
  }
}

},{"messageformat-parser":8,"reserved-words":10}],2:[function(require,module,exports){
/** @file messageformat.js - ICU PluralFormat + SelectFormat for JavaScript
 *
 * @author Alex Sexton - @SlexAxton, Eemeli Aro
 * @version 1.0.2
 * @copyright 2012-2016 Alex Sexton, Eemeli Aro, and Contributors
 * @license To use or fork, MIT. To contribute back, Dojo CLA
 */

var Compiler = require('./compiler');
var Runtime = require('./runtime');


/** Utility getter/wrapper for pluralization functions from
 *  {@link http://github.com/eemeli/make-plural.js make-plural}
 *
 * @private
 */
function getPluralFunc(locale, noPluralKeyChecks) {
  var plurals = require('make-plural/plurals');
  var pluralCategories = require('make-plural/pluralCategories');
  for (var l = locale; l; l = l.replace(/[-_]?[^-_]*$/, '')) {
    var pf = plurals[l];
    if (pf) {
      var pc = noPluralKeyChecks ? { cardinal: [], ordinal: [] } : (pluralCategories[l] || {});
      var fn = function() { return pf.apply(this, arguments); };
      fn.toString = function() { return pf.toString(); };
      fn.cardinal = pc.cardinal;
      fn.ordinal = pc.ordinal;
      return fn;
    }
  }
  throw new Error('Localisation function not found for locale ' + JSON.stringify(locale));
}


/** Create a new message formatter
 *
 *  If `locale` is not set, calls to `compile()` will fetch the default locale
 *  each time. A string `locale` will create a single-locale MessageFormat
 *  instance, with pluralisation rules fetched from the Unicode CLDR using
 *  {@link http://github.com/eemeli/make-plural.js make-plural}.
 *
 *  Using an array of strings as `locale` will create a MessageFormat object
 *  with multi-language support, with pluralisation rules fetched as above. To
 *  select which to use, use the second parameter of `compile()`, or use message
 *  keys corresponding to your locales.
 *
 *  Using an object `locale` with all properties of type `function` allows for
 *  the use of custom/externally defined pluralisation rules.
 *
 * @class
 * @param {string|string[]|Object.<string,function>} [locale] - The locale(s) to use
 */
function MessageFormat(locale) {
  this.pluralFuncs = {};
  if (locale) {
    if (typeof locale == 'string') {
      this.pluralFuncs[locale] = getPluralFunc(locale);
    } else if (Array.isArray(locale)) {
      locale.forEach(function(lc) { this.pluralFuncs[lc] = getPluralFunc(lc); }, this);
    } else if (typeof locale == 'object') {
      for (var lc in locale) if (locale.hasOwnProperty(lc)) {
        if (typeof locale[lc] != 'function') throw new Error('Expected function value for locale ' + JSON.stringify(lc));
        this.pluralFuncs[lc] = locale[lc];
      }
    }
  }
  this.fmt = {};
  this.runtime = new Runtime(this);
}


/** The default locale
 *
 *  Read by `compile()` when no locale has been previously set
 *
 * @memberof MessageFormat
 * @default 'en'
 */
MessageFormat.defaultLocale = 'en';


/** Escape special characaters
 *
 *  Prefix the characters `#`, `{`, `}` and `\` in the input string with a `\`.
 *  This will allow those characters to not be considered as MessageFormat
 *  control characters.
 *
 * @param {string} str - The input string
 * @returns {string} The escaped string
 */
MessageFormat.escape = function(str) {
  return str.replace(/[#{}\\]/g, '\\$&');
}


/** Default number formatting functions in the style of ICU's
 *  {@link http://icu-project.org/apiref/icu4j/com/ibm/icu/text/MessageFormat.html simpleArg syntax}
 *  implemented using the
 *  {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl Intl}
 *  object defined by ECMA-402.
 *
 *  **Note**: Intl is not defined in default Node until 0.11.15 / 0.12.0, so
 *  earlier versions require a {@link https://www.npmjs.com/package/intl polyfill}.
 *  Therefore {@link MessageFormat.intlSupport} needs to be true for these default
 *  functions to be available for inclusion in the output.
 *
 * @see MessageFormat#setIntlSupport
 *
 * @namespace
 */
MessageFormat.formatters = {


  /** Represent a number as an integer, percent or currency value
   *
   *  Available in MessageFormat strings as `{VAR, number, integer|percent|currency}`.
   *  Internally, calls Intl.NumberFormat with appropriate parameters. `currency` will
   *  default to USD; to change, set `MessageFormat#currency` to the appropriate
   *  three-letter currency code.
   *
   * @param {number} value - The value to operate on
   * @param {string} type - One of `'integer'`, `'percent'` , or `currency`
   *
   * @example
   * var mf = new MessageFormat('en').setIntlSupport(true);
   * mf.currency = 'EUR';  // needs to be set before first compile() call
   *
   * mf.compile('{N} is almost {N, number, integer}')({ N: 3.14 })
   * // '3.14 is almost 3'
   *
   * mf.compile('{P, number, percent} complete')({ P: 0.99 })
   * // '99% complete'
   *
   * mf.compile('The total is {V, number, currency}.')({ V: 5.5 })
   * // 'The total is €5.50.'
   */
  number: function(self) {
    return new Function("v,lc,p",
      "return new Intl.NumberFormat(lc,\n" +
      "    p=='integer' ? {maximumFractionDigits:0}\n" +
      "  : p=='percent' ? {style:'percent'}\n" +
      "  : p=='currency' ? {style:'currency', currency:'" + (self.currency || 'USD') + "', minimumFractionDigits:2, maximumFractionDigits:2}\n" +
      "  : {}).format(v)"
    );
  },


  /** Represent a date as a short/default/long/full string
   *
   * The input value needs to be in a form that the
   * {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date Date object}
   * can process using its single-argument form, `new Date(value)`.
   *
   * @param {number|string} value - Either a Unix epoch time in milliseconds, or a string value representing a date
   * @param {string} [type='default'] - One of `'short'`, `'default'`, `'long'` , or `full`
   *
   * @example
   * var mf = new MessageFormat(['en', 'fi']).setIntlSupport(true);
   *
   * mf.compile('Today is {T, date}')({ T: Date.now() })
   * // 'Today is Feb 21, 2016'
   *
   * mf.compile('Tänään on {T, date}', 'fi')({ T: Date.now() })
   * // 'Tänään on 21. helmikuuta 2016'
   *
   * mf.compile('Unix time started on {T, date, full}')({ T: 0 })
   * // 'Unix time started on Thursday, January 1, 1970'
   *
   * var cf = mf.compile('{sys} became operational on {d0, date, short}');
   * cf({ sys: 'HAL 9000', d0: '12 January 1999' })
   * // 'HAL 9000 became operational on 1/12/1999'
   */
  date: function(v,lc,p) {
    var o = {day:'numeric', month:'short', year:'numeric'};
    switch (p) {
      case 'full': o.weekday = 'long';
      case 'long': o.month = 'long'; break;
      case 'short': o.month = 'numeric';
    }
    return (new Date(v)).toLocaleDateString(lc, o)
  },


  /** Represent a time as a short/default/long string
   *
   * The input value needs to be in a form that the
   * {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date Date object}
   * can process using its single-argument form, `new Date(value)`.
   *
   * @param {number|string} value - Either a Unix epoch time in milliseconds, or a string value representing a date
   * @param {string} [type='default'] - One of `'short'`, `'default'`, `'long'` , or `full`
   *
   * @example
   * var mf = new MessageFormat(['en', 'fi']).setIntlSupport(true);
   *
   * mf.compile('The time is now {T, time}')({ T: Date.now() })
   * // 'The time is now 11:26:35 PM'
   *
   * mf.compile('Kello on nyt {T, time}', 'fi')({ T: Date.now() })
   * // 'Kello on nyt 23.26.35'
   *
   * var cf = mf.compile('The Eagle landed at {T, time, full} on {T, date, full}');
   * cf({ T: '1969-07-20 20:17:40 UTC' })
   * // 'The Eagle landed at 10:17:40 PM GMT+2 on Sunday, July 20, 1969'
   */
  time: function(v,lc,p) {
    var o = {second:'numeric', minute:'numeric', hour:'numeric'};
    switch (p) {
      case 'full': case 'long': o.timeZoneName = 'short'; break;
      case 'short': delete o.second;
    }
    return (new Date(v)).toLocaleTimeString(lc, o)
  }
};


/** Add custom formatter functions to this MessageFormat instance
 *
 *  The general syntax for calling a formatting function in MessageFormat is
 *  `{var, fn[, args]*}`, where `var` is the variable that will be set by the
 *  user code, `fn` determines the formatting function, and `args` is an
 *  optional comma-separated list of additional arguments.
 *
 *  In JavaScript, each formatting function is called with three parameters;
 *  the variable value `v`, the current locale `lc`, and (if set) `args` as a
 *  single string, or an array of strings. Formatting functions should not have
 *  side effects.
 *
 * @see MessageFormat.formatters
 *
 * @memberof MessageFormat
 * @param {Object.<string,function>} fmt - A map of formatting functions
 * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
 *
 * @example
 * var mf = new MessageFormat('en-GB');
 * mf.addFormatters({
 *   upcase: function(v) { return v.toUpperCase(); },
 *   locale: function(v, lc) { return lc; },
 *   prop: function(v, lc, p) { return v[p] }
 * });
 *
 * mf.compile('This is {VAR, upcase}.')({ VAR: 'big' })
 * // 'This is BIG.'
 *
 * mf.compile('The current locale is {_, locale}.')({ _: '' })
 * // 'The current locale is en-GB.'
 *
 * mf.compile('Answer: {obj, prop, a}')({ obj: {q: 3, a: 42} })
 * // 'Answer: 42'
 */
MessageFormat.prototype.addFormatters = function(fmt) {
  for (var name in fmt) if (fmt.hasOwnProperty(name)) {
    this.fmt[name] = fmt[name];
  }
  return this;
};


/** Disable the validation of plural & selectordinal keys
 *
 *  Previous versions of messageformat.js allowed the use of plural &
 *  selectordinal statements with any keys; now we throw an error when a
 *  statement uses a non-numerical key that will never be matched as a
 *  pluralization category for the current locale.
 *
 *  Use this method to disable the validation and allow usage as previously.
 *  To re-enable, you'll need to create a new MessageFormat instance.
 *
 * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
 *
 * @example
 * var mf = new MessageFormat('en');
 * var msg = '{X, plural, zero{no answers} one{an answer} other{# answers}}';
 *
 * mf.compile(msg);
 * // Error: Invalid key `zero` for argument `X`. Valid plural keys for this
 * //        locale are `one`, `other`, and explicit keys like `=0`.
 *
 * mf.disablePluralKeyChecks();
 * mf.compile(msg)({ X: 0 });
 * // '0 answers'
 */
MessageFormat.prototype.disablePluralKeyChecks = function() {
  this.noPluralKeyChecks = true;
  for (var lc in this.pluralFuncs) if (this.pluralFuncs.hasOwnProperty(lc)) {
    this.pluralFuncs[lc].cardinal = [];
    this.pluralFuncs[lc].ordinal = [];
  }
  return this;
};


/** Enable or disable the addition of Unicode control characters to all input
 *  to preserve the integrity of the output when mixing LTR and RTL text.
 *
 * @see http://cldr.unicode.org/development/development-process/design-proposals/bidi-handling-of-structured-text
 *
 * @memberof MessageFormat
 * @param {boolean} [enable=true]
 * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
 *
 * @example
 * // upper case stands for RTL characters, output is shown as rendered
 * var mf = new MessageFormat('en');
 *
 * mf.compile('{0} >> {1} >> {2}')(['first', 'SECOND', 'THIRD']);
 * // 'first >> THIRD << SECOND'
 *
 * mf.setBiDiSupport(true);
 * mf.compile('{0} >> {1} >> {2}')(['first', 'SECOND', 'THIRD']);
 * // 'first >> SECOND >> THIRD'
 */
MessageFormat.prototype.setBiDiSupport = function(enable) {
    this.bidiSupport = !!enable || (typeof enable == 'undefined');
    return this;
};


/** Enable or disable support for the default formatters, which require the
 *  `Intl` object. Note that this can't be autodetected, as the environment
 *  in which the formatted text is compiled into Javascript functions is not
 *  necessarily the same environment in which they will get executed.
 *
 * @see MessageFormat.formatters
 *
 * @memberof MessageFormat
 * @param {boolean} [enable=true]
 * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
 */
MessageFormat.prototype.setIntlSupport = function(enable) {
    this.intlSupport = !!enable || (typeof enable == 'undefined');
    return this;
};


/** According to the ICU MessageFormat spec, a `#` character directly inside a
 *  `plural` or `selectordinal` statement should be replaced by the number
 *  matching the surrounding statement. By default, messageformat.js will
 *  replace `#` signs with the value of the nearest surrounding `plural` or
 *  `selectordinal` statement.
 *
 *  Set this to true to follow the stricter ICU MessageFormat spec, and to
 *  throw a runtime error if `#` is used with non-numeric input.
 *
 * @memberof MessageFormat
 * @param {boolean} [enable=true]
 * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
 *
 * @example
 * var mf = new MessageFormat('en');
 *
 * var cookieMsg = '#: {X, plural, =0{no cookies} one{a cookie} other{# cookies}}';
 * mf.compile(cookieMsg)({ X: 3 });
 * // '#: 3 cookies'
 *
 * var pastryMsg = '{X, plural, one{{P, select, cookie{a cookie} other{a pie}}} other{{P, select, cookie{# cookies} other{# pies}}}}';
 * mf.compile(pastryMsg)({ X: 3, P: 'pie' });
 * // '3 pies'
 *
 * mf.setStrictNumberSign(true);
 * mf.compile(pastryMsg)({ X: 3, P: 'pie' });
 * // '# pies'
 */
MessageFormat.prototype.setStrictNumberSign = function(enable) {
    this.strictNumberSign = !!enable || (typeof enable == 'undefined');
    this.runtime.setStrictNumber(this.strictNumberSign);
    return this;
};


/** Compile messages into storable functions
 *
 *  If `messages` is a single string including ICU MessageFormat declarations,
 *  the result of `compile()` is a function taking a single Object parameter
 *  `d` representing each of the input's defined variables.
 *
 *  If `messages` is a hierarchical structure of such strings, the output of
 *  `compile()` will match that structure, with each string replaced by its
 *  corresponding JavaScript function.
 *
 *  If the input `messages` -- and therefore the output -- of `compile()` is an
 *  object, the output object will have a `toString(global)` method that may be
 *  used to store or cache the compiled functions to disk, for later inclusion
 *  in any JS environment, without a local MessageFormat instance required. Its
 *  `global` parameters sets the name (if any) of the resulting global variable,
 *  with special handling for `exports`, `module.exports`, and `export default`.
 *  If `global` does not contain a `.`, the output defaults to an UMD pattern.
 *
 *  If `locale` is not set, the first locale set in the object's constructor
 *  will be used by default; using a key at any depth of `messages` that is a
 *  declared locale will set its child elements to use that locale.
 *
 *  If `locale` is set, it is used for all messages. If the constructor
 *  declared any locales, `locale` needs to be one of them.
 *
 * @memberof MessageFormat
 * @param {string|Object} messages - The input message(s) to be compiled, in ICU MessageFormat
 * @param {string} [locale] - A locale to use for the messages
 * @returns {function|Object} The first match found for the given locale(s)
 *
 * @example
 * var mf = new MessageFormat('en');
 * var cf = mf.compile('A {TYPE} example.');
 *
 * cf({ TYPE: 'simple' })
 * // 'A simple example.'
 *
 * @example
 * var mf = new MessageFormat(['en', 'fi']);
 * var cf = mf.compile({
 *   en: { a: 'A {TYPE} example.',
 *         b: 'This is the {COUNT, selectordinal, one{#st} two{#nd} few{#rd} other{#th}} example.' },
 *   fi: { a: '{TYPE} esimerkki.',
 *         b: 'Tämä on {COUNT, selectordinal, other{#.}} esimerkki.' }
 * });
 *
 * cf.en.b({ COUNT: 2 })
 * // 'This is the 2nd example.'
 *
 * cf.fi.b({ COUNT: 2 })
 * // 'Tämä on 2. esimerkki.'
 *
 * @example
 * var fs = require('fs');
 * var mf = new MessageFormat('en').setIntlSupport();
 * var msgSet = {
 *   a: 'A {TYPE} example.',
 *   b: 'This has {COUNT, plural, one{one member} other{# members}}.',
 *   c: 'We have {P, number, percent} code coverage.'
 * };
 * var cfStr = mf.compile(msgSet).toString('module.exports');
 * fs.writeFileSync('messages.js', cfStr);
 * ...
 * var messages = require('./messages');
 *
 * messages.a({ TYPE: 'more complex' })
 * // 'A more complex example.'
 *
 * messages.b({ COUNT: 3 })
 * // 'This has 3 members.'
 */
MessageFormat.prototype.compile = function(messages, locale) {
  function _stringify(obj, level) {
    if (!level) level = 0;
    if (typeof obj != 'object') return obj;
    var o = [], indent = '';
    for (var i = 0; i < level; ++i) indent += '  ';
    for (var k in obj) o.push('\n' + indent + '  ' + Compiler.propname(k) + ': ' + _stringify(obj[k], level + 1));
    return '{' + o.join(',') + '\n' + indent + '}';
  }

  var pf;
  if (Object.keys(this.pluralFuncs).length == 0) {
    if (!locale) locale = MessageFormat.defaultLocale;
    pf = {};
    pf[locale] = getPluralFunc(locale, this.noPluralKeyChecks);
  } else if (locale) {
    pf = {};
    pf[locale] = this.pluralFuncs[locale];
    if (!pf[locale]) throw new Error('Locale ' + JSON.stringify(locale) + 'not found in ' + JSON.stringify(this.pluralFuncs) + '!');
  } else {
    pf = this.pluralFuncs;
    locale = Object.keys(pf)[0];
  }

  var compiler = new Compiler(this);
  var obj = compiler.compile(messages, locale, pf);

  if (typeof messages != 'object') {
    var fn = new Function(
        'number, plural, select, fmt', Compiler.funcname(locale),
        'return ' + obj);
    var rt = this.runtime;
    return fn(rt.number, rt.plural, rt.select, this.fmt, pf[locale]);
  }

  var rtStr = this.runtime.toString(pf, compiler) + '\n';
  var objStr = _stringify(obj);
  var result = new Function(rtStr + 'return ' + objStr)();
  if (result.hasOwnProperty('toString')) throw new Error('The top-level message key `toString` is reserved');

  result.toString = function(global) {
    switch (global || '') {
      case 'exports':
        var o = [];
        for (var k in obj) o.push(Compiler.propname(k, 'exports') + ' = ' + _stringify(obj[k]));
        return rtStr + o.join(';\n');
      case 'module.exports':
        return rtStr + 'module.exports = ' + objStr;
      case 'export default':
        return rtStr +  'export default ' + objStr;
      case '':
        return rtStr + 'return ' + objStr;
      default:
        if (global.indexOf('.') > -1) return rtStr + global + ' = ' + objStr;
        return rtStr + [
          '(function (root, G) {',
          '  if (typeof define === "function" && define.amd) { define(G); }',
          '  else if (typeof exports === "object") { module.exports = G; }',
          '  else { ' + Compiler.propname(global, 'root') + ' = G; }',
          '})(this, ' + objStr + ');'
        ].join('\n');
    }
  }
  return result;
}


module.exports = MessageFormat;

},{"./compiler":1,"./runtime":3,"make-plural/pluralCategories":6,"make-plural/plurals":7}],3:[function(require,module,exports){
var Compiler = require('./compiler');


/** A set of utility functions that are called by the compiled Javascript
 *  functions, these are included locally in the output of {@link
 *  MessageFormat#compile compile()}.
 *
 * @class
 * @param {MessageFormat} mf - A MessageFormat instance
 */
function Runtime(mf) {
  this.mf = mf;
  this.setStrictNumber(mf.strictNumberSign);
}

module.exports = Runtime;


/** Utility function for `#` in plural rules
 *
 *  Will throw an Error if `value` has a non-numeric value and `offset` is
 *  non-zero or {@link MessageFormat#setStrictNumberSign} is set.
 *
 * @function Runtime#number
 * @param {number} value - The value to operate on
 * @param {string} name - The name of the argument, used for error reporting
 * @param {number} [offset=0] - An optional offset, set by the surrounding context
 * @returns {number|string} The result of applying the offset to the input value
 */
function defaultNumber(value, name, offset) {
  if (!offset) return value;
  if (isNaN(value)) throw new Error('Can\'t apply offset:' + offset + ' to argument `' + name +
                                    '` with non-numerical value ' + JSON.stringify(value) + '.');
  return value - offset;
}


/** @private */
function strictNumber(value, name, offset) {
  if (isNaN(value)) throw new Error('Argument `' + name + '` has non-numerical value ' + JSON.stringify(value) + '.');
  return value - (offset || 0);
}


/** Set how strictly the {@link number} method parses its input.
 *
 *  According to the ICU MessageFormat spec, `#` can only be used to replace a
 *  number input of a `plural` statement. By default, messageformat.js does not
 *  throw a runtime error if you use non-numeric argument with a `plural` rule,
 *  unless rule also includes a non-zero `offset`.
 *
 *  This is called by {@link MessageFormat#setStrictNumberSign} to follow the
 *  stricter ICU MessageFormat spec.
 *
 * @param {boolean} [enable=false]
 */
Runtime.prototype.setStrictNumber = function(enable) {
  this.number = enable ? strictNumber : defaultNumber;
}


/** Utility function for `{N, plural|selectordinal, ...}`
 *
 * @param {number} value - The key to use to find a pluralization rule
 * @param {number} offset - An offset to apply to `value`
 * @param {function} lcfunc - A locale function from `pluralFuncs`
 * @param {Object.<string,string>} data - The object from which results are looked up
 * @param {?boolean} isOrdinal - If true, use ordinal rather than cardinal rules
 * @returns {string} The result of the pluralization
 */
Runtime.prototype.plural = function(value, offset, lcfunc, data, isOrdinal) {
  if ({}.hasOwnProperty.call(data, value)) return data[value];
  if (offset) value -= offset;
  var key = lcfunc(value, isOrdinal);
  if (key in data) return data[key];
  return data.other;
}


/** Utility function for `{N, select, ...}`
 *
 * @param {number} value - The key to use to find a selection
 * @param {Object.<string,string>} data - The object from which results are looked up
 * @returns {string} The result of the select statement
 */
Runtime.prototype.select = function(value, data) {
  if ({}.hasOwnProperty.call(data, value)) return data[value];
  return data.other;
}


/** @private */
Runtime.prototype.toString = function(pluralFuncs, compiler) {
  function _stringify(o, level) {
    if (typeof o != 'object') {
      var funcStr = o.toString().replace(/^(function )\w*/, '$1');
      var indent = /([ \t]*)\S.*$/.exec(funcStr);
      return indent ? funcStr.replace(new RegExp('^' + indent[1], 'mg'), '') : funcStr;
    }
    var s = [];
    for (var i in o) {
      if (level == 0) s.push('var ' + i + ' = ' + _stringify(o[i], level + 1) + ';\n');
      else s.push(Compiler.propname(i) + ': ' + _stringify(o[i], level + 1));
    }
    if (level == 0) return s.join('');
    if (s.length == 0) return '{}';
    var indent = '  '; while (--level) indent += '  ';
    return '{\n' + s.join(',\n').replace(/^/gm, indent) + '\n}';
  }

  var obj = {};
  Object.keys(compiler.locales).forEach(function(lc) { obj[Compiler.funcname(lc)] = pluralFuncs[lc]; });
  Object.keys(compiler.runtime).forEach(function(fn) { obj[fn] = this[fn]; }, this);
  var fmtKeys = Object.keys(compiler.formatters);
  var fmt = this.mf.fmt;
  if (fmtKeys.length) obj.fmt = fmtKeys.reduce(function(o, key) { o[key] = fmt[key]; return o; }, {});
  return _stringify(obj, 0);
}

},{"./compiler":1}],4:[function(require,module,exports){
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// when used in node, this will actually load the util module we depend on
// versus loading the builtin util module as happens otherwise
// this is a bug in node module loading as far as I am concerned
var util = require('util/');

var pSlice = Array.prototype.slice;
var hasOwn = Object.prototype.hasOwnProperty;

// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.

var assert = module.exports = ok;

// 2. The AssertionError is defined in assert.
// new assert.AssertionError({ message: message,
//                             actual: actual,
//                             expected: expected })

assert.AssertionError = function AssertionError(options) {
  this.name = 'AssertionError';
  this.actual = options.actual;
  this.expected = options.expected;
  this.operator = options.operator;
  if (options.message) {
    this.message = options.message;
    this.generatedMessage = false;
  } else {
    this.message = getMessage(this);
    this.generatedMessage = true;
  }
  var stackStartFunction = options.stackStartFunction || fail;

  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, stackStartFunction);
  }
  else {
    // non v8 browsers so we can have a stacktrace
    var err = new Error();
    if (err.stack) {
      var out = err.stack;

      // try to strip useless frames
      var fn_name = stackStartFunction.name;
      var idx = out.indexOf('\n' + fn_name);
      if (idx >= 0) {
        // once we have located the function frame
        // we need to strip out everything before it (and its line)
        var next_line = out.indexOf('\n', idx + 1);
        out = out.substring(next_line + 1);
      }

      this.stack = out;
    }
  }
};

// assert.AssertionError instanceof Error
util.inherits(assert.AssertionError, Error);

function replacer(key, value) {
  if (util.isUndefined(value)) {
    return '' + value;
  }
  if (util.isNumber(value) && !isFinite(value)) {
    return value.toString();
  }
  if (util.isFunction(value) || util.isRegExp(value)) {
    return value.toString();
  }
  return value;
}

function truncate(s, n) {
  if (util.isString(s)) {
    return s.length < n ? s : s.slice(0, n);
  } else {
    return s;
  }
}

function getMessage(self) {
  return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' +
         self.operator + ' ' +
         truncate(JSON.stringify(self.expected, replacer), 128);
}

// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.

// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided.  All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.

function fail(actual, expected, message, operator, stackStartFunction) {
  throw new assert.AssertionError({
    message: message,
    actual: actual,
    expected: expected,
    operator: operator,
    stackStartFunction: stackStartFunction
  });
}

// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;

// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, !!guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.

function ok(value, message) {
  if (!value) fail(value, true, message, '==', assert.ok);
}
assert.ok = ok;

// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);

assert.equal = function equal(actual, expected, message) {
  if (actual != expected) fail(actual, expected, message, '==', assert.equal);
};

// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);

assert.notEqual = function notEqual(actual, expected, message) {
  if (actual == expected) {
    fail(actual, expected, message, '!=', assert.notEqual);
  }
};

// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);

assert.deepEqual = function deepEqual(actual, expected, message) {
  if (!_deepEqual(actual, expected)) {
    fail(actual, expected, message, 'deepEqual', assert.deepEqual);
  }
};

function _deepEqual(actual, expected) {
  // 7.1. All identical values are equivalent, as determined by ===.
  if (actual === expected) {
    return true;

  } else if (util.isBuffer(actual) && util.isBuffer(expected)) {
    if (actual.length != expected.length) return false;

    for (var i = 0; i < actual.length; i++) {
      if (actual[i] !== expected[i]) return false;
    }

    return true;

  // 7.2. If the expected value is a Date object, the actual value is
  // equivalent if it is also a Date object that refers to the same time.
  } else if (util.isDate(actual) && util.isDate(expected)) {
    return actual.getTime() === expected.getTime();

  // 7.3 If the expected value is a RegExp object, the actual value is
  // equivalent if it is also a RegExp object with the same source and
  // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
  } else if (util.isRegExp(actual) && util.isRegExp(expected)) {
    return actual.source === expected.source &&
           actual.global === expected.global &&
           actual.multiline === expected.multiline &&
           actual.lastIndex === expected.lastIndex &&
           actual.ignoreCase === expected.ignoreCase;

  // 7.4. Other pairs that do not both pass typeof value == 'object',
  // equivalence is determined by ==.
  } else if (!util.isObject(actual) && !util.isObject(expected)) {
    return actual == expected;

  // 7.5 For all other Object pairs, including Array objects, equivalence is
  // determined by having the same number of owned properties (as verified
  // with Object.prototype.hasOwnProperty.call), the same set of keys
  // (although not necessarily the same order), equivalent values for every
  // corresponding key, and an identical 'prototype' property. Note: this
  // accounts for both named and indexed properties on Arrays.
  } else {
    return objEquiv(actual, expected);
  }
}

function isArguments(object) {
  return Object.prototype.toString.call(object) == '[object Arguments]';
}

function objEquiv(a, b) {
  if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b))
    return false;
  // an identical 'prototype' property.
  if (a.prototype !== b.prototype) return false;
  // if one is a primitive, the other must be same
  if (util.isPrimitive(a) || util.isPrimitive(b)) {
    return a === b;
  }
  var aIsArgs = isArguments(a),
      bIsArgs = isArguments(b);
  if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
    return false;
  if (aIsArgs) {
    a = pSlice.call(a);
    b = pSlice.call(b);
    return _deepEqual(a, b);
  }
  var ka = objectKeys(a),
      kb = objectKeys(b),
      key, i;
  // having the same number of owned properties (keys incorporates
  // hasOwnProperty)
  if (ka.length != kb.length)
    return false;
  //the same set of keys (although not necessarily the same order),
  ka.sort();
  kb.sort();
  //~~~cheap key test
  for (i = ka.length - 1; i >= 0; i--) {
    if (ka[i] != kb[i])
      return false;
  }
  //equivalent values for every corresponding key, and
  //~~~possibly expensive deep test
  for (i = ka.length - 1; i >= 0; i--) {
    key = ka[i];
    if (!_deepEqual(a[key], b[key])) return false;
  }
  return true;
}

// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);

assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
  if (_deepEqual(actual, expected)) {
    fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
  }
};

// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);

assert.strictEqual = function strictEqual(actual, expected, message) {
  if (actual !== expected) {
    fail(actual, expected, message, '===', assert.strictEqual);
  }
};

// 10. The strict non-equality assertion tests for strict inequality, as
// determined by !==.  assert.notStrictEqual(actual, expected, message_opt);

assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
  if (actual === expected) {
    fail(actual, expected, message, '!==', assert.notStrictEqual);
  }
};

function expectedException(actual, expected) {
  if (!actual || !expected) {
    return false;
  }

  if (Object.prototype.toString.call(expected) == '[object RegExp]') {
    return expected.test(actual);
  } else if (actual instanceof expected) {
    return true;
  } else if (expected.call({}, actual) === true) {
    return true;
  }

  return false;
}

function _throws(shouldThrow, block, expected, message) {
  var actual;

  if (util.isString(expected)) {
    message = expected;
    expected = null;
  }

  try {
    block();
  } catch (e) {
    actual = e;
  }

  message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
            (message ? ' ' + message : '.');

  if (shouldThrow && !actual) {
    fail(actual, expected, 'Missing expected exception' + message);
  }

  if (!shouldThrow && expectedException(actual, expected)) {
    fail(actual, expected, 'Got unwanted exception' + message);
  }

  if ((shouldThrow && actual && expected &&
      !expectedException(actual, expected)) || (!shouldThrow && actual)) {
    throw actual;
  }
}

// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);

assert["throws"] = function(block, /*optional*/error, /*optional*/message) {
  _throws.apply(this, [true].concat(pSlice.call(arguments)));
};

// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/message) {
  _throws.apply(this, [false].concat(pSlice.call(arguments)));
};

assert.ifError = function(err) { if (err) {throw err;}};

var objectKeys = Object.keys || function (obj) {
  var keys = [];
  for (var key in obj) {
    if (hasOwn.call(obj, key)) keys.push(key);
  }
  return keys;
};

},{"util/":13}],5:[function(require,module,exports){
if (typeof Object.create === 'function') {
  // implementation from standard node.js 'util' module
  module.exports = function inherits(ctor, superCtor) {
    ctor.super_ = superCtor
    ctor.prototype = Object.create(superCtor.prototype, {
      constructor: {
        value: ctor,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
  };
} else {
  // old school shim for old browsers
  module.exports = function inherits(ctor, superCtor) {
    ctor.super_ = superCtor
    var TempCtor = function () {}
    TempCtor.prototype = superCtor.prototype
    ctor.prototype = new TempCtor()
    ctor.prototype.constructor = ctor
  }
}

},{}],6:[function(require,module,exports){
var _cc = [
  {cardinal:["other"],ordinal:["other"]},
  {cardinal:["one","other"],ordinal:["other"]},
  {cardinal:["one","other"],ordinal:["one","other"]},
  {cardinal:["one","two","other"],ordinal:["other"]}
];

(function (root, pluralCategories) {
  if (typeof define === 'function' && define.amd) {
    define(pluralCategories);
  } else if (typeof exports === 'object') {
    module.exports = pluralCategories;
  } else {
    root.pluralCategories = pluralCategories;
  }
}(this, {
af: _cc[1],
ak: _cc[1],
am: _cc[1],
ar: {cardinal:["zero","one","two","few","many","other"],ordinal:["other"]},
as: {cardinal:["one","other"],ordinal:["one","two","few","many","other"]},
asa: _cc[1],
ast: _cc[1],
az: {cardinal:["one","other"],ordinal:["one","few","many","other"]},
be: {cardinal:["one","few","many","other"],ordinal:["few","other"]},
bem: _cc[1],
bez: _cc[1],
bg: _cc[1],
bh: _cc[1],
bm: _cc[0],
bn: {cardinal:["one","other"],ordinal:["one","two","few","many","other"]},
bo: _cc[0],
br: {cardinal:["one","two","few","many","other"],ordinal:["other"]},
brx: _cc[1],
bs: {cardinal:["one","few","other"],ordinal:["other"]},
ca: {cardinal:["one","other"],ordinal:["one","two","few","other"]},
ce: _cc[1],
cgg: _cc[1],
chr: _cc[1],
ckb: _cc[1],
cs: {cardinal:["one","few","many","other"],ordinal:["other"]},
cy: {cardinal:["zero","one","two","few","many","other"],ordinal:["zero","one","two","few","many","other"]},
da: _cc[1],
de: _cc[1],
dsb: {cardinal:["one","two","few","other"],ordinal:["other"]},
dv: _cc[1],
dz: _cc[0],
ee: _cc[1],
el: _cc[1],
en: {cardinal:["one","other"],ordinal:["one","two","few","other"]},
eo: _cc[1],
es: _cc[1],
et: _cc[1],
eu: _cc[1],
fa: _cc[1],
ff: _cc[1],
fi: _cc[1],
fil: _cc[2],
fo: _cc[1],
fr: _cc[2],
fur: _cc[1],
fy: _cc[1],
ga: {cardinal:["one","two","few","many","other"],ordinal:["one","other"]},
gd: {cardinal:["one","two","few","other"],ordinal:["other"]},
gl: _cc[1],
gsw: _cc[1],
gu: {cardinal:["one","other"],ordinal:["one","two","few","many","other"]},
guw: _cc[1],
gv: {cardinal:["one","two","few","many","other"],ordinal:["other"]},
ha: _cc[1],
haw: _cc[1],
he: {cardinal:["one","two","many","other"],ordinal:["other"]},
hi: {cardinal:["one","other"],ordinal:["one","two","few","many","other"]},
hr: {cardinal:["one","few","other"],ordinal:["other"]},
hsb: {cardinal:["one","two","few","other"],ordinal:["other"]},
hu: _cc[2],
hy: _cc[2],
id: _cc[0],
ig: _cc[0],
ii: _cc[0],
"in": _cc[0],
is: _cc[1],
it: {cardinal:["one","other"],ordinal:["many","other"]},
iu: _cc[3],
iw: {cardinal:["one","two","many","other"],ordinal:["other"]},
ja: _cc[0],
jbo: _cc[0],
jgo: _cc[1],
ji: _cc[1],
jmc: _cc[1],
jv: _cc[0],
jw: _cc[0],
ka: {cardinal:["one","other"],ordinal:["one","many","other"]},
kab: _cc[1],
kaj: _cc[1],
kcg: _cc[1],
kde: _cc[0],
kea: _cc[0],
kk: {cardinal:["one","other"],ordinal:["many","other"]},
kkj: _cc[1],
kl: _cc[1],
km: _cc[0],
kn: _cc[1],
ko: _cc[0],
ks: _cc[1],
ksb: _cc[1],
ksh: {cardinal:["zero","one","other"],ordinal:["other"]},
ku: _cc[1],
kw: _cc[3],
ky: _cc[1],
lag: {cardinal:["zero","one","other"],ordinal:["other"]},
lb: _cc[1],
lg: _cc[1],
lkt: _cc[0],
ln: _cc[1],
lo: {cardinal:["other"],ordinal:["one","other"]},
lt: {cardinal:["one","few","many","other"],ordinal:["other"]},
lv: {cardinal:["zero","one","other"],ordinal:["other"]},
mas: _cc[1],
mg: _cc[1],
mgo: _cc[1],
mk: {cardinal:["one","other"],ordinal:["one","two","many","other"]},
ml: _cc[1],
mn: _cc[1],
mo: {cardinal:["one","few","other"],ordinal:["one","other"]},
mr: {cardinal:["one","other"],ordinal:["one","two","few","other"]},
ms: {cardinal:["other"],ordinal:["one","other"]},
mt: {cardinal:["one","few","many","other"],ordinal:["other"]},
my: _cc[0],
nah: _cc[1],
naq: _cc[3],
nb: _cc[1],
nd: _cc[1],
ne: _cc[2],
nl: _cc[1],
nn: _cc[1],
nnh: _cc[1],
no: _cc[1],
nqo: _cc[0],
nr: _cc[1],
nso: _cc[1],
ny: _cc[1],
nyn: _cc[1],
om: _cc[1],
or: _cc[1],
os: _cc[1],
pa: _cc[1],
pap: _cc[1],
pl: {cardinal:["one","few","many","other"],ordinal:["other"]},
prg: {cardinal:["zero","one","other"],ordinal:["other"]},
ps: _cc[1],
pt: _cc[1],
"pt-PT": _cc[1],
rm: _cc[1],
ro: {cardinal:["one","few","other"],ordinal:["one","other"]},
rof: _cc[1],
root: _cc[0],
ru: {cardinal:["one","few","many","other"],ordinal:["other"]},
rwk: _cc[1],
sah: _cc[0],
saq: _cc[1],
sdh: _cc[1],
se: _cc[3],
seh: _cc[1],
ses: _cc[0],
sg: _cc[0],
sh: {cardinal:["one","few","other"],ordinal:["other"]},
shi: {cardinal:["one","few","other"],ordinal:["other"]},
si: _cc[1],
sk: {cardinal:["one","few","many","other"],ordinal:["other"]},
sl: {cardinal:["one","two","few","other"],ordinal:["other"]},
sma: _cc[3],
smi: _cc[3],
smj: _cc[3],
smn: _cc[3],
sms: _cc[3],
sn: _cc[1],
so: _cc[1],
sq: {cardinal:["one","other"],ordinal:["one","many","other"]},
sr: {cardinal:["one","few","other"],ordinal:["other"]},
ss: _cc[1],
ssy: _cc[1],
st: _cc[1],
sv: _cc[2],
sw: _cc[1],
syr: _cc[1],
ta: _cc[1],
te: _cc[1],
teo: _cc[1],
th: _cc[0],
ti: _cc[1],
tig: _cc[1],
tk: _cc[1],
tl: _cc[2],
tn: _cc[1],
to: _cc[0],
tr: _cc[1],
ts: _cc[1],
tzm: _cc[1],
ug: _cc[1],
uk: {cardinal:["one","few","many","other"],ordinal:["few","other"]},
ur: _cc[1],
uz: _cc[1],
ve: _cc[1],
vi: {cardinal:["other"],ordinal:["one","other"]},
vo: _cc[1],
vun: _cc[1],
wa: _cc[1],
wae: _cc[1],
wo: _cc[0],
xh: _cc[1],
xog: _cc[1],
yi: _cc[1],
yo: _cc[0],
zh: _cc[0],
zu: _cc[1]
}));

},{}],7:[function(require,module,exports){
var _cp = [
function(n, ord) {
  if (ord) return 'other';
  return 'other';
},
function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one' : 'other';
},
function(n, ord) {
  if (ord) return 'other';
  return ((n == 0
          || n == 1)) ? 'one' : 'other';
},
function(n, ord) {
  var s = String(n).split('.'), v0 = !s[1];
  if (ord) return 'other';
  return (n == 1 && v0) ? 'one' : 'other';
}
];

(function (root, plurals) {
  if (typeof define === 'function' && define.amd) {
    define(plurals);
  } else if (typeof exports === 'object') {
    module.exports = plurals;
  } else {
    root.plurals = plurals;
  }
}(this, {
af: _cp[1],

ak: _cp[2],

am: function(n, ord) {
  if (ord) return 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
},

ar: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n,
      n100 = t0 && s[0].slice(-2);
  if (ord) return 'other';
  return (n == 0) ? 'zero'
      : (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : ((n100 >= 3 && n100 <= 10)) ? 'few'
      : ((n100 >= 11 && n100 <= 99)) ? 'many'
      : 'other';
},

as: function(n, ord) {
  if (ord) return ((n == 1 || n == 5 || n == 7 || n == 8 || n == 9
          || n == 10)) ? 'one'
      : ((n == 2
          || n == 3)) ? 'two'
      : (n == 4) ? 'few'
      : (n == 6) ? 'many'
      : 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
},

asa: _cp[1],

ast: _cp[3],

az: function(n, ord) {
  var s = String(n).split('.'), i = s[0], i10 = i.slice(-1),
      i100 = i.slice(-2), i1000 = i.slice(-3);
  if (ord) return ((i10 == 1 || i10 == 2 || i10 == 5 || i10 == 7 || i10 == 8)
          || (i100 == 20 || i100 == 50 || i100 == 70
          || i100 == 80)) ? 'one'
      : ((i10 == 3 || i10 == 4) || (i1000 == 100 || i1000 == 200
          || i1000 == 300 || i1000 == 400 || i1000 == 500 || i1000 == 600 || i1000 == 700
          || i1000 == 800
          || i1000 == 900)) ? 'few'
      : (i == 0 || i10 == 6 || (i100 == 40 || i100 == 60
          || i100 == 90)) ? 'many'
      : 'other';
  return (n == 1) ? 'one' : 'other';
},

be: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1), n100 = t0 && s[0].slice(-2);
  if (ord) return ((n10 == 2
          || n10 == 3) && n100 != 12 && n100 != 13) ? 'few' : 'other';
  return (n10 == 1 && n100 != 11) ? 'one'
      : ((n10 >= 2 && n10 <= 4) && (n100 < 12
          || n100 > 14)) ? 'few'
      : (t0 && n10 == 0 || (n10 >= 5 && n10 <= 9)
          || (n100 >= 11 && n100 <= 14)) ? 'many'
      : 'other';
},

bem: _cp[1],

bez: _cp[1],

bg: _cp[1],

bh: _cp[2],

bm: _cp[0],

bn: function(n, ord) {
  if (ord) return ((n == 1 || n == 5 || n == 7 || n == 8 || n == 9
          || n == 10)) ? 'one'
      : ((n == 2
          || n == 3)) ? 'two'
      : (n == 4) ? 'few'
      : (n == 6) ? 'many'
      : 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
},

bo: _cp[0],

br: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1), n100 = t0 && s[0].slice(-2),
      n1000000 = t0 && s[0].slice(-6);
  if (ord) return 'other';
  return (n10 == 1 && n100 != 11 && n100 != 71 && n100 != 91) ? 'one'
      : (n10 == 2 && n100 != 12 && n100 != 72 && n100 != 92) ? 'two'
      : (((n10 == 3 || n10 == 4) || n10 == 9) && (n100 < 10
          || n100 > 19) && (n100 < 70 || n100 > 79) && (n100 < 90
          || n100 > 99)) ? 'few'
      : (n != 0 && t0 && n1000000 == 0) ? 'many'
      : 'other';
},

brx: _cp[1],

bs: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i10 = i.slice(-1), i100 = i.slice(-2), f10 = f.slice(-1), f100 = f.slice(-2);
  if (ord) return 'other';
  return (v0 && i10 == 1 && i100 != 11
          || f10 == 1 && f100 != 11) ? 'one'
      : (v0 && (i10 >= 2 && i10 <= 4) && (i100 < 12 || i100 > 14)
          || (f10 >= 2 && f10 <= 4) && (f100 < 12
          || f100 > 14)) ? 'few'
      : 'other';
},

ca: function(n, ord) {
  var s = String(n).split('.'), v0 = !s[1];
  if (ord) return ((n == 1
          || n == 3)) ? 'one'
      : (n == 2) ? 'two'
      : (n == 4) ? 'few'
      : 'other';
  return (n == 1 && v0) ? 'one' : 'other';
},

ce: _cp[1],

cgg: _cp[1],

chr: _cp[1],

ckb: _cp[1],

cs: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1];
  if (ord) return 'other';
  return (n == 1 && v0) ? 'one'
      : ((i >= 2 && i <= 4) && v0) ? 'few'
      : (!v0) ? 'many'
      : 'other';
},

cy: function(n, ord) {
  if (ord) return ((n == 0 || n == 7 || n == 8
          || n == 9)) ? 'zero'
      : (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : ((n == 3
          || n == 4)) ? 'few'
      : ((n == 5
          || n == 6)) ? 'many'
      : 'other';
  return (n == 0) ? 'zero'
      : (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : (n == 3) ? 'few'
      : (n == 6) ? 'many'
      : 'other';
},

da: function(n, ord) {
  var s = String(n).split('.'), i = s[0], t0 = Number(s[0]) == n;
  if (ord) return 'other';
  return (n == 1 || !t0 && (i == 0
          || i == 1)) ? 'one' : 'other';
},

de: _cp[3],

dsb: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i100 = i.slice(-2), f100 = f.slice(-2);
  if (ord) return 'other';
  return (v0 && i100 == 1
          || f100 == 1) ? 'one'
      : (v0 && i100 == 2
          || f100 == 2) ? 'two'
      : (v0 && (i100 == 3 || i100 == 4) || (f100 == 3
          || f100 == 4)) ? 'few'
      : 'other';
},

dv: _cp[1],

dz: _cp[0],

ee: _cp[1],

el: _cp[1],

en: function(n, ord) {
  var s = String(n).split('.'), v0 = !s[1], t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1), n100 = t0 && s[0].slice(-2);
  if (ord) return (n10 == 1 && n100 != 11) ? 'one'
      : (n10 == 2 && n100 != 12) ? 'two'
      : (n10 == 3 && n100 != 13) ? 'few'
      : 'other';
  return (n == 1 && v0) ? 'one' : 'other';
},

eo: _cp[1],

es: _cp[1],

et: _cp[3],

eu: _cp[1],

fa: function(n, ord) {
  if (ord) return 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
},

ff: function(n, ord) {
  if (ord) return 'other';
  return (n >= 0 && n < 2) ? 'one' : 'other';
},

fi: _cp[3],

fil: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i10 = i.slice(-1), f10 = f.slice(-1);
  if (ord) return (n == 1) ? 'one' : 'other';
  return (v0 && (i == 1 || i == 2 || i == 3)
          || v0 && i10 != 4 && i10 != 6 && i10 != 9
          || !v0 && f10 != 4 && f10 != 6 && f10 != 9) ? 'one' : 'other';
},

fo: _cp[1],

fr: function(n, ord) {
  if (ord) return (n == 1) ? 'one' : 'other';
  return (n >= 0 && n < 2) ? 'one' : 'other';
},

fur: _cp[1],

fy: _cp[3],

ga: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n;
  if (ord) return (n == 1) ? 'one' : 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : ((t0 && n >= 3 && n <= 6)) ? 'few'
      : ((t0 && n >= 7 && n <= 10)) ? 'many'
      : 'other';
},

gd: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n;
  if (ord) return 'other';
  return ((n == 1
          || n == 11)) ? 'one'
      : ((n == 2
          || n == 12)) ? 'two'
      : (((t0 && n >= 3 && n <= 10)
          || (t0 && n >= 13 && n <= 19))) ? 'few'
      : 'other';
},

gl: _cp[3],

gsw: _cp[1],

gu: function(n, ord) {
  if (ord) return (n == 1) ? 'one'
      : ((n == 2
          || n == 3)) ? 'two'
      : (n == 4) ? 'few'
      : (n == 6) ? 'many'
      : 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
},

guw: _cp[2],

gv: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1], i10 = i.slice(-1),
      i100 = i.slice(-2);
  if (ord) return 'other';
  return (v0 && i10 == 1) ? 'one'
      : (v0 && i10 == 2) ? 'two'
      : (v0 && (i100 == 0 || i100 == 20 || i100 == 40 || i100 == 60
          || i100 == 80)) ? 'few'
      : (!v0) ? 'many'
      : 'other';
},

ha: _cp[1],

haw: _cp[1],

he: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1], t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1);
  if (ord) return 'other';
  return (n == 1 && v0) ? 'one'
      : (i == 2 && v0) ? 'two'
      : (v0 && (n < 0
          || n > 10) && t0 && n10 == 0) ? 'many'
      : 'other';
},

hi: function(n, ord) {
  if (ord) return (n == 1) ? 'one'
      : ((n == 2
          || n == 3)) ? 'two'
      : (n == 4) ? 'few'
      : (n == 6) ? 'many'
      : 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
},

hr: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i10 = i.slice(-1), i100 = i.slice(-2), f10 = f.slice(-1), f100 = f.slice(-2);
  if (ord) return 'other';
  return (v0 && i10 == 1 && i100 != 11
          || f10 == 1 && f100 != 11) ? 'one'
      : (v0 && (i10 >= 2 && i10 <= 4) && (i100 < 12 || i100 > 14)
          || (f10 >= 2 && f10 <= 4) && (f100 < 12
          || f100 > 14)) ? 'few'
      : 'other';
},

hsb: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i100 = i.slice(-2), f100 = f.slice(-2);
  if (ord) return 'other';
  return (v0 && i100 == 1
          || f100 == 1) ? 'one'
      : (v0 && i100 == 2
          || f100 == 2) ? 'two'
      : (v0 && (i100 == 3 || i100 == 4) || (f100 == 3
          || f100 == 4)) ? 'few'
      : 'other';
},

hu: function(n, ord) {
  if (ord) return ((n == 1
          || n == 5)) ? 'one' : 'other';
  return (n == 1) ? 'one' : 'other';
},

hy: function(n, ord) {
  if (ord) return (n == 1) ? 'one' : 'other';
  return (n >= 0 && n < 2) ? 'one' : 'other';
},

id: _cp[0],

ig: _cp[0],

ii: _cp[0],

"in": _cp[0],

is: function(n, ord) {
  var s = String(n).split('.'), i = s[0], t0 = Number(s[0]) == n,
      i10 = i.slice(-1), i100 = i.slice(-2);
  if (ord) return 'other';
  return (t0 && i10 == 1 && i100 != 11
          || !t0) ? 'one' : 'other';
},

it: function(n, ord) {
  var s = String(n).split('.'), v0 = !s[1];
  if (ord) return ((n == 11 || n == 8 || n == 80
          || n == 800)) ? 'many' : 'other';
  return (n == 1 && v0) ? 'one' : 'other';
},

iu: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

iw: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1], t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1);
  if (ord) return 'other';
  return (n == 1 && v0) ? 'one'
      : (i == 2 && v0) ? 'two'
      : (v0 && (n < 0
          || n > 10) && t0 && n10 == 0) ? 'many'
      : 'other';
},

ja: _cp[0],

jbo: _cp[0],

jgo: _cp[1],

ji: _cp[3],

jmc: _cp[1],

jv: _cp[0],

jw: _cp[0],

ka: function(n, ord) {
  var s = String(n).split('.'), i = s[0], i100 = i.slice(-2);
  if (ord) return (i == 1) ? 'one'
      : (i == 0 || ((i100 >= 2 && i100 <= 20) || i100 == 40 || i100 == 60
          || i100 == 80)) ? 'many'
      : 'other';
  return (n == 1) ? 'one' : 'other';
},

kab: function(n, ord) {
  if (ord) return 'other';
  return (n >= 0 && n < 2) ? 'one' : 'other';
},

kaj: _cp[1],

kcg: _cp[1],

kde: _cp[0],

kea: _cp[0],

kk: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1);
  if (ord) return (n10 == 6 || n10 == 9
          || t0 && n10 == 0 && n != 0) ? 'many' : 'other';
  return (n == 1) ? 'one' : 'other';
},

kkj: _cp[1],

kl: _cp[1],

km: _cp[0],

kn: function(n, ord) {
  if (ord) return 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
},

ko: _cp[0],

ks: _cp[1],

ksb: _cp[1],

ksh: function(n, ord) {
  if (ord) return 'other';
  return (n == 0) ? 'zero'
      : (n == 1) ? 'one'
      : 'other';
},

ku: _cp[1],

kw: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

ky: _cp[1],

lag: function(n, ord) {
  var s = String(n).split('.'), i = s[0];
  if (ord) return 'other';
  return (n == 0) ? 'zero'
      : ((i == 0
          || i == 1) && n != 0) ? 'one'
      : 'other';
},

lb: _cp[1],

lg: _cp[1],

lkt: _cp[0],

ln: _cp[2],

lo: function(n, ord) {
  if (ord) return (n == 1) ? 'one' : 'other';
  return 'other';
},

lt: function(n, ord) {
  var s = String(n).split('.'), f = s[1] || '', t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1), n100 = t0 && s[0].slice(-2);
  if (ord) return 'other';
  return (n10 == 1 && (n100 < 11
          || n100 > 19)) ? 'one'
      : ((n10 >= 2 && n10 <= 9) && (n100 < 11
          || n100 > 19)) ? 'few'
      : (f != 0) ? 'many'
      : 'other';
},

lv: function(n, ord) {
  var s = String(n).split('.'), f = s[1] || '', v = f.length,
      t0 = Number(s[0]) == n, n10 = t0 && s[0].slice(-1),
      n100 = t0 && s[0].slice(-2), f100 = f.slice(-2), f10 = f.slice(-1);
  if (ord) return 'other';
  return (t0 && n10 == 0 || (n100 >= 11 && n100 <= 19)
          || v == 2 && (f100 >= 11 && f100 <= 19)) ? 'zero'
      : (n10 == 1 && n100 != 11 || v == 2 && f10 == 1 && f100 != 11
          || v != 2 && f10 == 1) ? 'one'
      : 'other';
},

mas: _cp[1],

mg: _cp[2],

mgo: _cp[1],

mk: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i10 = i.slice(-1), i100 = i.slice(-2), f10 = f.slice(-1);
  if (ord) return (i10 == 1 && i100 != 11) ? 'one'
      : (i10 == 2 && i100 != 12) ? 'two'
      : ((i10 == 7
          || i10 == 8) && i100 != 17 && i100 != 18) ? 'many'
      : 'other';
  return (v0 && i10 == 1
          || f10 == 1) ? 'one' : 'other';
},

ml: _cp[1],

mn: _cp[1],

mo: function(n, ord) {
  var s = String(n).split('.'), v0 = !s[1], t0 = Number(s[0]) == n,
      n100 = t0 && s[0].slice(-2);
  if (ord) return (n == 1) ? 'one' : 'other';
  return (n == 1 && v0) ? 'one'
      : (!v0 || n == 0
          || n != 1 && (n100 >= 1 && n100 <= 19)) ? 'few'
      : 'other';
},

mr: function(n, ord) {
  if (ord) return (n == 1) ? 'one'
      : ((n == 2
          || n == 3)) ? 'two'
      : (n == 4) ? 'few'
      : 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
},

ms: function(n, ord) {
  if (ord) return (n == 1) ? 'one' : 'other';
  return 'other';
},

mt: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n,
      n100 = t0 && s[0].slice(-2);
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 0
          || (n100 >= 2 && n100 <= 10)) ? 'few'
      : ((n100 >= 11 && n100 <= 19)) ? 'many'
      : 'other';
},

my: _cp[0],

nah: _cp[1],

naq: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

nb: _cp[1],

nd: _cp[1],

ne: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n;
  if (ord) return ((t0 && n >= 1 && n <= 4)) ? 'one' : 'other';
  return (n == 1) ? 'one' : 'other';
},

nl: _cp[3],

nn: _cp[1],

nnh: _cp[1],

no: _cp[1],

nqo: _cp[0],

nr: _cp[1],

nso: _cp[2],

ny: _cp[1],

nyn: _cp[1],

om: _cp[1],

or: _cp[1],

os: _cp[1],

pa: _cp[2],

pap: _cp[1],

pl: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1], i10 = i.slice(-1),
      i100 = i.slice(-2);
  if (ord) return 'other';
  return (n == 1 && v0) ? 'one'
      : (v0 && (i10 >= 2 && i10 <= 4) && (i100 < 12
          || i100 > 14)) ? 'few'
      : (v0 && i != 1 && (i10 == 0 || i10 == 1)
          || v0 && (i10 >= 5 && i10 <= 9)
          || v0 && (i100 >= 12 && i100 <= 14)) ? 'many'
      : 'other';
},

prg: function(n, ord) {
  var s = String(n).split('.'), f = s[1] || '', v = f.length,
      t0 = Number(s[0]) == n, n10 = t0 && s[0].slice(-1),
      n100 = t0 && s[0].slice(-2), f100 = f.slice(-2), f10 = f.slice(-1);
  if (ord) return 'other';
  return (t0 && n10 == 0 || (n100 >= 11 && n100 <= 19)
          || v == 2 && (f100 >= 11 && f100 <= 19)) ? 'zero'
      : (n10 == 1 && n100 != 11 || v == 2 && f10 == 1 && f100 != 11
          || v != 2 && f10 == 1) ? 'one'
      : 'other';
},

ps: _cp[1],

pt: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n;
  if (ord) return 'other';
  return ((t0 && n >= 0 && n <= 2) && n != 2) ? 'one' : 'other';
},

"pt-PT": _cp[3],

rm: _cp[1],

ro: function(n, ord) {
  var s = String(n).split('.'), v0 = !s[1], t0 = Number(s[0]) == n,
      n100 = t0 && s[0].slice(-2);
  if (ord) return (n == 1) ? 'one' : 'other';
  return (n == 1 && v0) ? 'one'
      : (!v0 || n == 0
          || n != 1 && (n100 >= 1 && n100 <= 19)) ? 'few'
      : 'other';
},

rof: _cp[1],

root: _cp[0],

ru: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1], i10 = i.slice(-1),
      i100 = i.slice(-2);
  if (ord) return 'other';
  return (v0 && i10 == 1 && i100 != 11) ? 'one'
      : (v0 && (i10 >= 2 && i10 <= 4) && (i100 < 12
          || i100 > 14)) ? 'few'
      : (v0 && i10 == 0 || v0 && (i10 >= 5 && i10 <= 9)
          || v0 && (i100 >= 11 && i100 <= 14)) ? 'many'
      : 'other';
},

rwk: _cp[1],

sah: _cp[0],

saq: _cp[1],

sdh: _cp[1],

se: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

seh: _cp[1],

ses: _cp[0],

sg: _cp[0],

sh: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i10 = i.slice(-1), i100 = i.slice(-2), f10 = f.slice(-1), f100 = f.slice(-2);
  if (ord) return 'other';
  return (v0 && i10 == 1 && i100 != 11
          || f10 == 1 && f100 != 11) ? 'one'
      : (v0 && (i10 >= 2 && i10 <= 4) && (i100 < 12 || i100 > 14)
          || (f10 >= 2 && f10 <= 4) && (f100 < 12
          || f100 > 14)) ? 'few'
      : 'other';
},

shi: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n;
  if (ord) return 'other';
  return (n >= 0 && n <= 1) ? 'one'
      : ((t0 && n >= 2 && n <= 10)) ? 'few'
      : 'other';
},

si: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '';
  if (ord) return 'other';
  return ((n == 0 || n == 1)
          || i == 0 && f == 1) ? 'one' : 'other';
},

sk: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1];
  if (ord) return 'other';
  return (n == 1 && v0) ? 'one'
      : ((i >= 2 && i <= 4) && v0) ? 'few'
      : (!v0) ? 'many'
      : 'other';
},

sl: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1], i100 = i.slice(-2);
  if (ord) return 'other';
  return (v0 && i100 == 1) ? 'one'
      : (v0 && i100 == 2) ? 'two'
      : (v0 && (i100 == 3 || i100 == 4)
          || !v0) ? 'few'
      : 'other';
},

sma: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

smi: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

smj: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

smn: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

sms: function(n, ord) {
  if (ord) return 'other';
  return (n == 1) ? 'one'
      : (n == 2) ? 'two'
      : 'other';
},

sn: _cp[1],

so: _cp[1],

sq: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1), n100 = t0 && s[0].slice(-2);
  if (ord) return (n == 1) ? 'one'
      : (n10 == 4 && n100 != 14) ? 'many'
      : 'other';
  return (n == 1) ? 'one' : 'other';
},

sr: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i10 = i.slice(-1), i100 = i.slice(-2), f10 = f.slice(-1), f100 = f.slice(-2);
  if (ord) return 'other';
  return (v0 && i10 == 1 && i100 != 11
          || f10 == 1 && f100 != 11) ? 'one'
      : (v0 && (i10 >= 2 && i10 <= 4) && (i100 < 12 || i100 > 14)
          || (f10 >= 2 && f10 <= 4) && (f100 < 12
          || f100 > 14)) ? 'few'
      : 'other';
},

ss: _cp[1],

ssy: _cp[1],

st: _cp[1],

sv: function(n, ord) {
  var s = String(n).split('.'), v0 = !s[1], t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1), n100 = t0 && s[0].slice(-2);
  if (ord) return ((n10 == 1
          || n10 == 2) && n100 != 11 && n100 != 12) ? 'one' : 'other';
  return (n == 1 && v0) ? 'one' : 'other';
},

sw: _cp[3],

syr: _cp[1],

ta: _cp[1],

te: _cp[1],

teo: _cp[1],

th: _cp[0],

ti: _cp[2],

tig: _cp[1],

tk: _cp[1],

tl: function(n, ord) {
  var s = String(n).split('.'), i = s[0], f = s[1] || '', v0 = !s[1],
      i10 = i.slice(-1), f10 = f.slice(-1);
  if (ord) return (n == 1) ? 'one' : 'other';
  return (v0 && (i == 1 || i == 2 || i == 3)
          || v0 && i10 != 4 && i10 != 6 && i10 != 9
          || !v0 && f10 != 4 && f10 != 6 && f10 != 9) ? 'one' : 'other';
},

tn: _cp[1],

to: _cp[0],

tr: _cp[1],

ts: _cp[1],

tzm: function(n, ord) {
  var s = String(n).split('.'), t0 = Number(s[0]) == n;
  if (ord) return 'other';
  return ((n == 0 || n == 1)
          || (t0 && n >= 11 && n <= 99)) ? 'one' : 'other';
},

ug: _cp[1],

uk: function(n, ord) {
  var s = String(n).split('.'), i = s[0], v0 = !s[1], t0 = Number(s[0]) == n,
      n10 = t0 && s[0].slice(-1), n100 = t0 && s[0].slice(-2), i10 = i.slice(-1),
      i100 = i.slice(-2);
  if (ord) return (n10 == 3 && n100 != 13) ? 'few' : 'other';
  return (v0 && i10 == 1 && i100 != 11) ? 'one'
      : (v0 && (i10 >= 2 && i10 <= 4) && (i100 < 12
          || i100 > 14)) ? 'few'
      : (v0 && i10 == 0 || v0 && (i10 >= 5 && i10 <= 9)
          || v0 && (i100 >= 11 && i100 <= 14)) ? 'many'
      : 'other';
},

ur: _cp[3],

uz: _cp[1],

ve: _cp[1],

vi: function(n, ord) {
  if (ord) return (n == 1) ? 'one' : 'other';
  return 'other';
},

vo: _cp[1],

vun: _cp[1],

wa: _cp[2],

wae: _cp[1],

wo: _cp[0],

xh: _cp[1],

xog: _cp[1],

yi: _cp[3],

yo: _cp[0],

zh: _cp[0],

zu: function(n, ord) {
  if (ord) return 'other';
  return (n >= 0 && n <= 1) ? 'one' : 'other';
}
}));

},{}],8:[function(require,module,exports){
/*
 * Generated by PEG.js 0.10.0.
 *
 * http://pegjs.org/
 */

"use strict";

function peg$subclass(child, parent) {
  function ctor() { this.constructor = child; }
  ctor.prototype = parent.prototype;
  child.prototype = new ctor();
}

function peg$SyntaxError(message, expected, found, location) {
  this.message  = message;
  this.expected = expected;
  this.found    = found;
  this.location = location;
  this.name     = "SyntaxError";

  if (typeof Error.captureStackTrace === "function") {
    Error.captureStackTrace(this, peg$SyntaxError);
  }
}

peg$subclass(peg$SyntaxError, Error);

peg$SyntaxError.buildMessage = function(expected, found) {
  var DESCRIBE_EXPECTATION_FNS = {
        literal: function(expectation) {
          return "\"" + literalEscape(expectation.text) + "\"";
        },

        "class": function(expectation) {
          var escapedParts = "",
              i;

          for (i = 0; i < expectation.parts.length; i++) {
            escapedParts += expectation.parts[i] instanceof Array
              ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1])
              : classEscape(expectation.parts[i]);
          }

          return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
        },

        any: function(expectation) {
          return "any character";
        },

        end: function(expectation) {
          return "end of input";
        },

        other: function(expectation) {
          return expectation.description;
        }
      };

  function hex(ch) {
    return ch.charCodeAt(0).toString(16).toUpperCase();
  }

  function literalEscape(s) {
    return s
      .replace(/\\/g, '\\\\')
      .replace(/"/g,  '\\"')
      .replace(/\0/g, '\\0')
      .replace(/\t/g, '\\t')
      .replace(/\n/g, '\\n')
      .replace(/\r/g, '\\r')
      .replace(/[\x00-\x0F]/g,          function(ch) { return '\\x0' + hex(ch); })
      .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x'  + hex(ch); });
  }

  function classEscape(s) {
    return s
      .replace(/\\/g, '\\\\')
      .replace(/\]/g, '\\]')
      .replace(/\^/g, '\\^')
      .replace(/-/g,  '\\-')
      .replace(/\0/g, '\\0')
      .replace(/\t/g, '\\t')
      .replace(/\n/g, '\\n')
      .replace(/\r/g, '\\r')
      .replace(/[\x00-\x0F]/g,          function(ch) { return '\\x0' + hex(ch); })
      .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x'  + hex(ch); });
  }

  function describeExpectation(expectation) {
    return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
  }

  function describeExpected(expected) {
    var descriptions = new Array(expected.length),
        i, j;

    for (i = 0; i < expected.length; i++) {
      descriptions[i] = describeExpectation(expected[i]);
    }

    descriptions.sort();

    if (descriptions.length > 0) {
      for (i = 1, j = 1; i < descriptions.length; i++) {
        if (descriptions[i - 1] !== descriptions[i]) {
          descriptions[j] = descriptions[i];
          j++;
        }
      }
      descriptions.length = j;
    }

    switch (descriptions.length) {
      case 1:
        return descriptions[0];

      case 2:
        return descriptions[0] + " or " + descriptions[1];

      default:
        return descriptions.slice(0, -1).join(", ")
          + ", or "
          + descriptions[descriptions.length - 1];
    }
  }

  function describeFound(found) {
    return found ? "\"" + literalEscape(found) + "\"" : "end of input";
  }

  return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
};

function peg$parse(input, options) {
  options = options !== void 0 ? options : {};

  var peg$FAILED = {},

      peg$startRuleFunctions = { start: peg$parsestart },
      peg$startRuleFunction  = peg$parsestart,

      peg$c0 = "#",
      peg$c1 = peg$literalExpectation("#", false),
      peg$c2 = function() { return { type: 'octothorpe' }; },
      peg$c3 = function(str) { return str.join(''); },
      peg$c4 = "{",
      peg$c5 = peg$literalExpectation("{", false),
      peg$c6 = "}",
      peg$c7 = peg$literalExpectation("}", false),
      peg$c8 = function(arg) {
          return {
            type: 'argument',
            arg: arg
          };
        },
      peg$c9 = ",",
      peg$c10 = peg$literalExpectation(",", false),
      peg$c11 = "select",
      peg$c12 = peg$literalExpectation("select", false),
      peg$c13 = function(arg, cases) {
          return {
            type: 'select',
            arg: arg,
            cases: cases
          };
        },
      peg$c14 = "plural",
      peg$c15 = peg$literalExpectation("plural", false),
      peg$c16 = "selectordinal",
      peg$c17 = peg$literalExpectation("selectordinal", false),
      peg$c18 = function(arg, type, offset, cases) {
          var ls = ((type === 'selectordinal') ? options.ordinal : options.cardinal)
                   || ['zero', 'one', 'two', 'few', 'many', 'other'];
          if (ls && ls.length) cases.forEach(function(c) {
            if (isNaN(c.key) && ls.indexOf(c.key) < 0) throw new Error(
              'Invalid key `' + c.key + '` for argument `' + arg + '`.' +
              ' Valid ' + type + ' keys for this locale are `' + ls.join('`, `') +
              '`, and explicit keys like `=0`.');
          });
          return {
            type: type,
            arg: arg,
            offset: offset || 0,
            cases: cases
          };
        },
      peg$c19 = function(arg, key, params) {
          return {
            type: 'function',
            arg: arg,
            key: key,
            params: params
          };
        },
      peg$c20 = /^[0-9a-zA-Z$_]/,
      peg$c21 = peg$classExpectation([["0", "9"], ["a", "z"], ["A", "Z"], "$", "_"], false, false),
      peg$c22 = /^[^ \t\n\r,.+={}]/,
      peg$c23 = peg$classExpectation([" ", "\t", "\n", "\r", ",", ".", "+", "=", "{", "}"], true, false),
      peg$c24 = function(key, tokens) { return { key: key, tokens: tokens }; },
      peg$c25 = function(tokens) { return tokens; },
      peg$c26 = "offset",
      peg$c27 = peg$literalExpectation("offset", false),
      peg$c28 = ":",
      peg$c29 = peg$literalExpectation(":", false),
      peg$c30 = function(d) { return d; },
      peg$c31 = "=",
      peg$c32 = peg$literalExpectation("=", false),
      peg$c33 = function(p) { return p; },
      peg$c34 = /^[^{}#\\\0-\x08\x0E-\x1F\x7F]/,
      peg$c35 = peg$classExpectation(["{", "}", "#", "\\", ["\0", "\b"], ["\x0E", "\x1F"], "\x7F"], true, false),
      peg$c36 = "\\\\",
      peg$c37 = peg$literalExpectation("\\\\", false),
      peg$c38 = function() { return '\\'; },
      peg$c39 = "\\#",
      peg$c40 = peg$literalExpectation("\\#", false),
      peg$c41 = function() { return '#'; },
      peg$c42 = "\\{",
      peg$c43 = peg$literalExpectation("\\{", false),
      peg$c44 = function() { return '\u007B'; },
      peg$c45 = "\\}",
      peg$c46 = peg$literalExpectation("\\}", false),
      peg$c47 = function() { return '\u007D'; },
      peg$c48 = "\\u",
      peg$c49 = peg$literalExpectation("\\u", false),
      peg$c50 = function(h1, h2, h3, h4) {
            return String.fromCharCode(parseInt('0x' + h1 + h2 + h3 + h4));
          },
      peg$c51 = /^[0-9]/,
      peg$c52 = peg$classExpectation([["0", "9"]], false, false),
      peg$c53 = /^[0-9a-fA-F]/,
      peg$c54 = peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false),
      peg$c55 = /^[ \t\n\r]/,
      peg$c56 = peg$classExpectation([" ", "\t", "\n", "\r"], false, false),

      peg$currPos          = 0,
      peg$savedPos         = 0,
      peg$posDetailsCache  = [{ line: 1, column: 1 }],
      peg$maxFailPos       = 0,
      peg$maxFailExpected  = [],
      peg$silentFails      = 0,

      peg$result;

  if ("startRule" in options) {
    if (!(options.startRule in peg$startRuleFunctions)) {
      throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
    }

    peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
  }

  function text() {
    return input.substring(peg$savedPos, peg$currPos);
  }

  function location() {
    return peg$computeLocation(peg$savedPos, peg$currPos);
  }

  function expected(description, location) {
    location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)

    throw peg$buildStructuredError(
      [peg$otherExpectation(description)],
      input.substring(peg$savedPos, peg$currPos),
      location
    );
  }

  function error(message, location) {
    location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)

    throw peg$buildSimpleError(message, location);
  }

  function peg$literalExpectation(text, ignoreCase) {
    return { type: "literal", text: text, ignoreCase: ignoreCase };
  }

  function peg$classExpectation(parts, inverted, ignoreCase) {
    return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
  }

  function peg$anyExpectation() {
    return { type: "any" };
  }

  function peg$endExpectation() {
    return { type: "end" };
  }

  function peg$otherExpectation(description) {
    return { type: "other", description: description };
  }

  function peg$computePosDetails(pos) {
    var details = peg$posDetailsCache[pos], p;

    if (details) {
      return details;
    } else {
      p = pos - 1;
      while (!peg$posDetailsCache[p]) {
        p--;
      }

      details = peg$posDetailsCache[p];
      details = {
        line:   details.line,
        column: details.column
      };

      while (p < pos) {
        if (input.charCodeAt(p) === 10) {
          details.line++;
          details.column = 1;
        } else {
          details.column++;
        }

        p++;
      }

      peg$posDetailsCache[pos] = details;
      return details;
    }
  }

  function peg$computeLocation(startPos, endPos) {
    var startPosDetails = peg$computePosDetails(startPos),
        endPosDetails   = peg$computePosDetails(endPos);

    return {
      start: {
        offset: startPos,
        line:   startPosDetails.line,
        column: startPosDetails.column
      },
      end: {
        offset: endPos,
        line:   endPosDetails.line,
        column: endPosDetails.column
      }
    };
  }

  function peg$fail(expected) {
    if (peg$currPos < peg$maxFailPos) { return; }

    if (peg$currPos > peg$maxFailPos) {
      peg$maxFailPos = peg$currPos;
      peg$maxFailExpected = [];
    }

    peg$maxFailExpected.push(expected);
  }

  function peg$buildSimpleError(message, location) {
    return new peg$SyntaxError(message, null, null, location);
  }

  function peg$buildStructuredError(expected, found, location) {
    return new peg$SyntaxError(
      peg$SyntaxError.buildMessage(expected, found),
      expected,
      found,
      location
    );
  }

  function peg$parsestart() {
    var s0, s1;

    s0 = [];
    s1 = peg$parsetoken();
    while (s1 !== peg$FAILED) {
      s0.push(s1);
      s1 = peg$parsetoken();
    }

    return s0;
  }

  function peg$parsetoken() {
    var s0, s1, s2;

    s0 = peg$parseargument();
    if (s0 === peg$FAILED) {
      s0 = peg$parseselect();
      if (s0 === peg$FAILED) {
        s0 = peg$parseplural();
        if (s0 === peg$FAILED) {
          s0 = peg$parsefunction();
          if (s0 === peg$FAILED) {
            s0 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 35) {
              s1 = peg$c0;
              peg$currPos++;
            } else {
              s1 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c1); }
            }
            if (s1 !== peg$FAILED) {
              peg$savedPos = s0;
              s1 = peg$c2();
            }
            s0 = s1;
            if (s0 === peg$FAILED) {
              s0 = peg$currPos;
              s1 = [];
              s2 = peg$parsechar();
              if (s2 !== peg$FAILED) {
                while (s2 !== peg$FAILED) {
                  s1.push(s2);
                  s2 = peg$parsechar();
                }
              } else {
                s1 = peg$FAILED;
              }
              if (s1 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c3(s1);
              }
              s0 = s1;
            }
          }
        }
      }
    }

    return s0;
  }

  function peg$parseargument() {
    var s0, s1, s2, s3, s4, s5;

    s0 = peg$currPos;
    if (input.charCodeAt(peg$currPos) === 123) {
      s1 = peg$c4;
      peg$currPos++;
    } else {
      s1 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c5); }
    }
    if (s1 !== peg$FAILED) {
      s2 = peg$parse_();
      if (s2 !== peg$FAILED) {
        s3 = peg$parseid();
        if (s3 !== peg$FAILED) {
          s4 = peg$parse_();
          if (s4 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 125) {
              s5 = peg$c6;
              peg$currPos++;
            } else {
              s5 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c7); }
            }
            if (s5 !== peg$FAILED) {
              peg$savedPos = s0;
              s1 = peg$c8(s3);
              s0 = s1;
            } else {
              peg$currPos = s0;
              s0 = peg$FAILED;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parseselect() {
    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13;

    s0 = peg$currPos;
    if (input.charCodeAt(peg$currPos) === 123) {
      s1 = peg$c4;
      peg$currPos++;
    } else {
      s1 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c5); }
    }
    if (s1 !== peg$FAILED) {
      s2 = peg$parse_();
      if (s2 !== peg$FAILED) {
        s3 = peg$parseid();
        if (s3 !== peg$FAILED) {
          s4 = peg$parse_();
          if (s4 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 44) {
              s5 = peg$c9;
              peg$currPos++;
            } else {
              s5 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c10); }
            }
            if (s5 !== peg$FAILED) {
              s6 = peg$parse_();
              if (s6 !== peg$FAILED) {
                if (input.substr(peg$currPos, 6) === peg$c11) {
                  s7 = peg$c11;
                  peg$currPos += 6;
                } else {
                  s7 = peg$FAILED;
                  if (peg$silentFails === 0) { peg$fail(peg$c12); }
                }
                if (s7 !== peg$FAILED) {
                  s8 = peg$parse_();
                  if (s8 !== peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 44) {
                      s9 = peg$c9;
                      peg$currPos++;
                    } else {
                      s9 = peg$FAILED;
                      if (peg$silentFails === 0) { peg$fail(peg$c10); }
                    }
                    if (s9 !== peg$FAILED) {
                      s10 = peg$parse_();
                      if (s10 !== peg$FAILED) {
                        s11 = [];
                        s12 = peg$parseselectCase();
                        if (s12 !== peg$FAILED) {
                          while (s12 !== peg$FAILED) {
                            s11.push(s12);
                            s12 = peg$parseselectCase();
                          }
                        } else {
                          s11 = peg$FAILED;
                        }
                        if (s11 !== peg$FAILED) {
                          s12 = peg$parse_();
                          if (s12 !== peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 125) {
                              s13 = peg$c6;
                              peg$currPos++;
                            } else {
                              s13 = peg$FAILED;
                              if (peg$silentFails === 0) { peg$fail(peg$c7); }
                            }
                            if (s13 !== peg$FAILED) {
                              peg$savedPos = s0;
                              s1 = peg$c13(s3, s11);
                              s0 = s1;
                            } else {
                              peg$currPos = s0;
                              s0 = peg$FAILED;
                            }
                          } else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                          }
                        } else {
                          peg$currPos = s0;
                          s0 = peg$FAILED;
                        }
                      } else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                      }
                    } else {
                      peg$currPos = s0;
                      s0 = peg$FAILED;
                    }
                  } else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                  }
                } else {
                  peg$currPos = s0;
                  s0 = peg$FAILED;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$FAILED;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$FAILED;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parseplural() {
    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14;

    s0 = peg$currPos;
    if (input.charCodeAt(peg$currPos) === 123) {
      s1 = peg$c4;
      peg$currPos++;
    } else {
      s1 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c5); }
    }
    if (s1 !== peg$FAILED) {
      s2 = peg$parse_();
      if (s2 !== peg$FAILED) {
        s3 = peg$parseid();
        if (s3 !== peg$FAILED) {
          s4 = peg$parse_();
          if (s4 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 44) {
              s5 = peg$c9;
              peg$currPos++;
            } else {
              s5 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c10); }
            }
            if (s5 !== peg$FAILED) {
              s6 = peg$parse_();
              if (s6 !== peg$FAILED) {
                if (input.substr(peg$currPos, 6) === peg$c14) {
                  s7 = peg$c14;
                  peg$currPos += 6;
                } else {
                  s7 = peg$FAILED;
                  if (peg$silentFails === 0) { peg$fail(peg$c15); }
                }
                if (s7 === peg$FAILED) {
                  if (input.substr(peg$currPos, 13) === peg$c16) {
                    s7 = peg$c16;
                    peg$currPos += 13;
                  } else {
                    s7 = peg$FAILED;
                    if (peg$silentFails === 0) { peg$fail(peg$c17); }
                  }
                }
                if (s7 !== peg$FAILED) {
                  s8 = peg$parse_();
                  if (s8 !== peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 44) {
                      s9 = peg$c9;
                      peg$currPos++;
                    } else {
                      s9 = peg$FAILED;
                      if (peg$silentFails === 0) { peg$fail(peg$c10); }
                    }
                    if (s9 !== peg$FAILED) {
                      s10 = peg$parse_();
                      if (s10 !== peg$FAILED) {
                        s11 = peg$parseoffset();
                        if (s11 === peg$FAILED) {
                          s11 = null;
                        }
                        if (s11 !== peg$FAILED) {
                          s12 = [];
                          s13 = peg$parsepluralCase();
                          if (s13 !== peg$FAILED) {
                            while (s13 !== peg$FAILED) {
                              s12.push(s13);
                              s13 = peg$parsepluralCase();
                            }
                          } else {
                            s12 = peg$FAILED;
                          }
                          if (s12 !== peg$FAILED) {
                            s13 = peg$parse_();
                            if (s13 !== peg$FAILED) {
                              if (input.charCodeAt(peg$currPos) === 125) {
                                s14 = peg$c6;
                                peg$currPos++;
                              } else {
                                s14 = peg$FAILED;
                                if (peg$silentFails === 0) { peg$fail(peg$c7); }
                              }
                              if (s14 !== peg$FAILED) {
                                peg$savedPos = s0;
                                s1 = peg$c18(s3, s7, s11, s12);
                                s0 = s1;
                              } else {
                                peg$currPos = s0;
                                s0 = peg$FAILED;
                              }
                            } else {
                              peg$currPos = s0;
                              s0 = peg$FAILED;
                            }
                          } else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                          }
                        } else {
                          peg$currPos = s0;
                          s0 = peg$FAILED;
                        }
                      } else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                      }
                    } else {
                      peg$currPos = s0;
                      s0 = peg$FAILED;
                    }
                  } else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                  }
                } else {
                  peg$currPos = s0;
                  s0 = peg$FAILED;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$FAILED;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$FAILED;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parsefunction() {
    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;

    s0 = peg$currPos;
    if (input.charCodeAt(peg$currPos) === 123) {
      s1 = peg$c4;
      peg$currPos++;
    } else {
      s1 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c5); }
    }
    if (s1 !== peg$FAILED) {
      s2 = peg$parse_();
      if (s2 !== peg$FAILED) {
        s3 = peg$parseid();
        if (s3 !== peg$FAILED) {
          s4 = peg$parse_();
          if (s4 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 44) {
              s5 = peg$c9;
              peg$currPos++;
            } else {
              s5 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c10); }
            }
            if (s5 !== peg$FAILED) {
              s6 = peg$parse_();
              if (s6 !== peg$FAILED) {
                s7 = peg$parseid();
                if (s7 !== peg$FAILED) {
                  s8 = peg$parse_();
                  if (s8 !== peg$FAILED) {
                    s9 = [];
                    s10 = peg$parsefunctionParams();
                    while (s10 !== peg$FAILED) {
                      s9.push(s10);
                      s10 = peg$parsefunctionParams();
                    }
                    if (s9 !== peg$FAILED) {
                      if (input.charCodeAt(peg$currPos) === 125) {
                        s10 = peg$c6;
                        peg$currPos++;
                      } else {
                        s10 = peg$FAILED;
                        if (peg$silentFails === 0) { peg$fail(peg$c7); }
                      }
                      if (s10 !== peg$FAILED) {
                        peg$savedPos = s0;
                        s1 = peg$c19(s3, s7, s9);
                        s0 = s1;
                      } else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                      }
                    } else {
                      peg$currPos = s0;
                      s0 = peg$FAILED;
                    }
                  } else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                  }
                } else {
                  peg$currPos = s0;
                  s0 = peg$FAILED;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$FAILED;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$FAILED;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parseid() {
    var s0, s1, s2, s3, s4;

    s0 = peg$currPos;
    s1 = peg$currPos;
    if (peg$c20.test(input.charAt(peg$currPos))) {
      s2 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s2 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c21); }
    }
    if (s2 !== peg$FAILED) {
      s3 = [];
      if (peg$c22.test(input.charAt(peg$currPos))) {
        s4 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s4 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c23); }
      }
      while (s4 !== peg$FAILED) {
        s3.push(s4);
        if (peg$c22.test(input.charAt(peg$currPos))) {
          s4 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s4 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c23); }
        }
      }
      if (s3 !== peg$FAILED) {
        s2 = [s2, s3];
        s1 = s2;
      } else {
        peg$currPos = s1;
        s1 = peg$FAILED;
      }
    } else {
      peg$currPos = s1;
      s1 = peg$FAILED;
    }
    if (s1 !== peg$FAILED) {
      s0 = input.substring(s0, peg$currPos);
    } else {
      s0 = s1;
    }

    return s0;
  }

  function peg$parseselectCase() {
    var s0, s1, s2, s3, s4;

    s0 = peg$currPos;
    s1 = peg$parse_();
    if (s1 !== peg$FAILED) {
      s2 = peg$parseid();
      if (s2 !== peg$FAILED) {
        s3 = peg$parse_();
        if (s3 !== peg$FAILED) {
          s4 = peg$parsecaseTokens();
          if (s4 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c24(s2, s4);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parsepluralCase() {
    var s0, s1, s2, s3, s4;

    s0 = peg$currPos;
    s1 = peg$parse_();
    if (s1 !== peg$FAILED) {
      s2 = peg$parsepluralKey();
      if (s2 !== peg$FAILED) {
        s3 = peg$parse_();
        if (s3 !== peg$FAILED) {
          s4 = peg$parsecaseTokens();
          if (s4 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c24(s2, s4);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parsecaseTokens() {
    var s0, s1, s2, s3, s4, s5;

    s0 = peg$currPos;
    if (input.charCodeAt(peg$currPos) === 123) {
      s1 = peg$c4;
      peg$currPos++;
    } else {
      s1 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c5); }
    }
    if (s1 !== peg$FAILED) {
      s2 = peg$currPos;
      s3 = peg$parse_();
      if (s3 !== peg$FAILED) {
        s4 = peg$currPos;
        peg$silentFails++;
        if (input.charCodeAt(peg$currPos) === 123) {
          s5 = peg$c4;
          peg$currPos++;
        } else {
          s5 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c5); }
        }
        peg$silentFails--;
        if (s5 !== peg$FAILED) {
          peg$currPos = s4;
          s4 = void 0;
        } else {
          s4 = peg$FAILED;
        }
        if (s4 !== peg$FAILED) {
          s3 = [s3, s4];
          s2 = s3;
        } else {
          peg$currPos = s2;
          s2 = peg$FAILED;
        }
      } else {
        peg$currPos = s2;
        s2 = peg$FAILED;
      }
      if (s2 === peg$FAILED) {
        s2 = null;
      }
      if (s2 !== peg$FAILED) {
        s3 = [];
        s4 = peg$parsetoken();
        while (s4 !== peg$FAILED) {
          s3.push(s4);
          s4 = peg$parsetoken();
        }
        if (s3 !== peg$FAILED) {
          s4 = peg$parse_();
          if (s4 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 125) {
              s5 = peg$c6;
              peg$currPos++;
            } else {
              s5 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c7); }
            }
            if (s5 !== peg$FAILED) {
              peg$savedPos = s0;
              s1 = peg$c25(s3);
              s0 = s1;
            } else {
              peg$currPos = s0;
              s0 = peg$FAILED;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parseoffset() {
    var s0, s1, s2, s3, s4, s5, s6, s7;

    s0 = peg$currPos;
    s1 = peg$parse_();
    if (s1 !== peg$FAILED) {
      if (input.substr(peg$currPos, 6) === peg$c26) {
        s2 = peg$c26;
        peg$currPos += 6;
      } else {
        s2 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c27); }
      }
      if (s2 !== peg$FAILED) {
        s3 = peg$parse_();
        if (s3 !== peg$FAILED) {
          if (input.charCodeAt(peg$currPos) === 58) {
            s4 = peg$c28;
            peg$currPos++;
          } else {
            s4 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c29); }
          }
          if (s4 !== peg$FAILED) {
            s5 = peg$parse_();
            if (s5 !== peg$FAILED) {
              s6 = peg$parsedigits();
              if (s6 !== peg$FAILED) {
                s7 = peg$parse_();
                if (s7 !== peg$FAILED) {
                  peg$savedPos = s0;
                  s1 = peg$c30(s6);
                  s0 = s1;
                } else {
                  peg$currPos = s0;
                  s0 = peg$FAILED;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$FAILED;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$FAILED;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parsepluralKey() {
    var s0, s1, s2;

    s0 = peg$parseid();
    if (s0 === peg$FAILED) {
      s0 = peg$currPos;
      if (input.charCodeAt(peg$currPos) === 61) {
        s1 = peg$c31;
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c32); }
      }
      if (s1 !== peg$FAILED) {
        s2 = peg$parsedigits();
        if (s2 !== peg$FAILED) {
          peg$savedPos = s0;
          s1 = peg$c30(s2);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    }

    return s0;
  }

  function peg$parsefunctionParams() {
    var s0, s1, s2, s3, s4, s5;

    s0 = peg$currPos;
    s1 = peg$parse_();
    if (s1 !== peg$FAILED) {
      if (input.charCodeAt(peg$currPos) === 44) {
        s2 = peg$c9;
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c10); }
      }
      if (s2 !== peg$FAILED) {
        s3 = peg$parse_();
        if (s3 !== peg$FAILED) {
          s4 = peg$parseid();
          if (s4 !== peg$FAILED) {
            s5 = peg$parse_();
            if (s5 !== peg$FAILED) {
              peg$savedPos = s0;
              s1 = peg$c33(s4);
              s0 = s1;
            } else {
              peg$currPos = s0;
              s0 = peg$FAILED;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }

    return s0;
  }

  function peg$parsechar() {
    var s0, s1, s2, s3, s4, s5;

    if (peg$c34.test(input.charAt(peg$currPos))) {
      s0 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s0 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c35); }
    }
    if (s0 === peg$FAILED) {
      s0 = peg$currPos;
      if (input.substr(peg$currPos, 2) === peg$c36) {
        s1 = peg$c36;
        peg$currPos += 2;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c37); }
      }
      if (s1 !== peg$FAILED) {
        peg$savedPos = s0;
        s1 = peg$c38();
      }
      s0 = s1;
      if (s0 === peg$FAILED) {
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 2) === peg$c39) {
          s1 = peg$c39;
          peg$currPos += 2;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c40); }
        }
        if (s1 !== peg$FAILED) {
          peg$savedPos = s0;
          s1 = peg$c41();
        }
        s0 = s1;
        if (s0 === peg$FAILED) {
          s0 = peg$currPos;
          if (input.substr(peg$currPos, 2) === peg$c42) {
            s1 = peg$c42;
            peg$currPos += 2;
          } else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c43); }
          }
          if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c44();
          }
          s0 = s1;
          if (s0 === peg$FAILED) {
            s0 = peg$currPos;
            if (input.substr(peg$currPos, 2) === peg$c45) {
              s1 = peg$c45;
              peg$currPos += 2;
            } else {
              s1 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c46); }
            }
            if (s1 !== peg$FAILED) {
              peg$savedPos = s0;
              s1 = peg$c47();
            }
            s0 = s1;
            if (s0 === peg$FAILED) {
              s0 = peg$currPos;
              if (input.substr(peg$currPos, 2) === peg$c48) {
                s1 = peg$c48;
                peg$currPos += 2;
              } else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) { peg$fail(peg$c49); }
              }
              if (s1 !== peg$FAILED) {
                s2 = peg$parsehexDigit();
                if (s2 !== peg$FAILED) {
                  s3 = peg$parsehexDigit();
                  if (s3 !== peg$FAILED) {
                    s4 = peg$parsehexDigit();
                    if (s4 !== peg$FAILED) {
                      s5 = peg$parsehexDigit();
                      if (s5 !== peg$FAILED) {
                        peg$savedPos = s0;
                        s1 = peg$c50(s2, s3, s4, s5);
                        s0 = s1;
                      } else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                      }
                    } else {
                      peg$currPos = s0;
                      s0 = peg$FAILED;
                    }
                  } else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                  }
                } else {
                  peg$currPos = s0;
                  s0 = peg$FAILED;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$FAILED;
              }
            }
          }
        }
      }
    }

    return s0;
  }

  function peg$parsedigits() {
    var s0, s1, s2;

    s0 = peg$currPos;
    s1 = [];
    if (peg$c51.test(input.charAt(peg$currPos))) {
      s2 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s2 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c52); }
    }
    if (s2 !== peg$FAILED) {
      while (s2 !== peg$FAILED) {
        s1.push(s2);
        if (peg$c51.test(input.charAt(peg$currPos))) {
          s2 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s2 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c52); }
        }
      }
    } else {
      s1 = peg$FAILED;
    }
    if (s1 !== peg$FAILED) {
      s0 = input.substring(s0, peg$currPos);
    } else {
      s0 = s1;
    }

    return s0;
  }

  function peg$parsehexDigit() {
    var s0;

    if (peg$c53.test(input.charAt(peg$currPos))) {
      s0 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s0 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c54); }
    }

    return s0;
  }

  function peg$parse_() {
    var s0, s1, s2;

    s0 = peg$currPos;
    s1 = [];
    if (peg$c55.test(input.charAt(peg$currPos))) {
      s2 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s2 = peg$FAILED;
      if (peg$silentFails === 0) { peg$fail(peg$c56); }
    }
    while (s2 !== peg$FAILED) {
      s1.push(s2);
      if (peg$c55.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c56); }
      }
    }
    if (s1 !== peg$FAILED) {
      s0 = input.substring(s0, peg$currPos);
    } else {
      s0 = s1;
    }

    return s0;
  }

  peg$result = peg$startRuleFunction();

  if (peg$result !== peg$FAILED && peg$currPos === input.length) {
    return peg$result;
  } else {
    if (peg$result !== peg$FAILED && peg$currPos < input.length) {
      peg$fail(peg$endExpectation());
    }

    throw peg$buildStructuredError(
      peg$maxFailExpected,
      peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
      peg$maxFailPos < input.length
        ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
        : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
    );
  }
}

module.exports = {
  SyntaxError: peg$SyntaxError,
  parse:       peg$parse
};

},{}],9:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};

// cached from whatever global is present so that test runners that stub it
// don't break things.  But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals.  It's inside a
// function because try/catches deoptimize in certain engines.

var cachedSetTimeout;
var cachedClearTimeout;

function defaultSetTimout() {
    throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
    throw new Error('clearTimeout has not been defined');
}
(function () {
    try {
        if (typeof setTimeout === 'function') {
            cachedSetTimeout = setTimeout;
        } else {
            cachedSetTimeout = defaultSetTimout;
        }
    } catch (e) {
        cachedSetTimeout = defaultSetTimout;
    }
    try {
        if (typeof clearTimeout === 'function') {
            cachedClearTimeout = clearTimeout;
        } else {
            cachedClearTimeout = defaultClearTimeout;
        }
    } catch (e) {
        cachedClearTimeout = defaultClearTimeout;
    }
} ())
function runTimeout(fun) {
    if (cachedSetTimeout === setTimeout) {
        //normal enviroments in sane situations
        return setTimeout(fun, 0);
    }
    // if setTimeout wasn't available but was latter defined
    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
        cachedSetTimeout = setTimeout;
        return setTimeout(fun, 0);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedSetTimeout(fun, 0);
    } catch(e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
            return cachedSetTimeout.call(null, fun, 0);
        } catch(e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
            return cachedSetTimeout.call(this, fun, 0);
        }
    }


}
function runClearTimeout(marker) {
    if (cachedClearTimeout === clearTimeout) {
        //normal enviroments in sane situations
        return clearTimeout(marker);
    }
    // if clearTimeout wasn't available but was latter defined
    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
        cachedClearTimeout = clearTimeout;
        return clearTimeout(marker);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedClearTimeout(marker);
    } catch (e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
            return cachedClearTimeout.call(null, marker);
        } catch (e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
            return cachedClearTimeout.call(this, marker);
        }
    }



}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;

function cleanUpNextTick() {
    if (!draining || !currentQueue) {
        return;
    }
    draining = false;
    if (currentQueue.length) {
        queue = currentQueue.concat(queue);
    } else {
        queueIndex = -1;
    }
    if (queue.length) {
        drainQueue();
    }
}

function drainQueue() {
    if (draining) {
        return;
    }
    var timeout = runTimeout(cleanUpNextTick);
    draining = true;

    var len = queue.length;
    while(len) {
        currentQueue = queue;
        queue = [];
        while (++queueIndex < len) {
            if (currentQueue) {
                currentQueue[queueIndex].run();
            }
        }
        queueIndex = -1;
        len = queue.length;
    }
    currentQueue = null;
    draining = false;
    runClearTimeout(timeout);
}

process.nextTick = function (fun) {
    var args = new Array(arguments.length - 1);
    if (arguments.length > 1) {
        for (var i = 1; i < arguments.length; i++) {
            args[i - 1] = arguments[i];
        }
    }
    queue.push(new Item(fun, args));
    if (queue.length === 1 && !draining) {
        runTimeout(drainQueue);
    }
};

// v8 likes predictible objects
function Item(fun, array) {
    this.fun = fun;
    this.array = array;
}
Item.prototype.run = function () {
    this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};

function noop() {}

process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;

process.binding = function (name) {
    throw new Error('process.binding is not supported');
};

process.cwd = function () { return '/' };
process.chdir = function (dir) {
    throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };

},{}],10:[function(require,module,exports){
module.exports = require('./reserved-words');

},{"./reserved-words":11}],11:[function(require,module,exports){
var assert = require('assert');

/**
 * Structure for storing keywords.
 *
 * @typedef {Object.<String,Boolean>} KeywordsHash
 */

/**
 * ECMAScript dialects.
 *
 * @const
 * @type {Object.<String,Number|String>} - keys as readable names and values as versions
 */
var DIALECTS = {
    es3: 3,
    es5: 5,
    es2015: 6,
    es7: 7,

    // aliases
    es6: 6,
    'default': 5,
    next: 6
};

/**
 * ECMAScript reserved words.
 *
 * @type {Object.<String,KeywordsHash>}
 */
var KEYWORDS = exports.KEYWORDS = {};

/**
 * Check word for being an reserved word.
 *
 * @param {String} word - word to check
 * @param {String|Number} [dialect] - dialect or version
 * @param {Boolean} [strict] - strict mode
 * @returns {?Boolean}
 */
exports.check = function check(word, dialect, strict) {
    dialect = dialect || DIALECTS["default"];
    var version = DIALECTS[dialect] || dialect;

    if (strict && version >= 5) {
        version += '-strict';
    }

    assert(KEYWORDS[version], 'Unknown dialect');

    return KEYWORDS[version][word];
};

/**
 * Reserved Words for ES3
 *
 * ECMA-262 3rd: 7.5.1
 * http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf
 *
 * @type {KeywordsHash}
 */
KEYWORDS['3'] = _hash(
    // Keyword, ECMA-262 3rd: 7.5.2
    'break    else       new     var',
    'case     finally    return  void',
    'catch    for        switch  while',
    'continue function   this    with',
    'default  if         throw',
    'delete   in         try',
    'do       instanceof typeof',
    // FutureReservedWord, ECMA-262 3rd 7.5.3
    'abstract enum       int        short',
    'boolean  export     interface  static',
    'byte     extends    long       super',
    'char     final      native     synchronized',
    'class    float      package    throws',
    'const    goto       private    transient',
    'debugger implements protected  volatile',
    'double   import     public',
    // NullLiteral & BooleanLiteral
    'null true false'
);

/**
 * Reserved Words for ES5.
 *
 * http://es5.github.io/#x7.6.1
 *
 * @type {KeywordsHash}
 */
KEYWORDS['5'] = _hash(
    // Keyword
    'break    do       instanceof typeof',
    'case     else     new        var',
    'catch    finally  return     void',
    'continue for      switch     while',
    'debugger function this       with',
    'default  if       throw',
    'delete   in       try',
    // FutureReservedWord
    'class enum extends super',
    'const export import',
    // NullLiteral & BooleanLiteral
    'null true false'
);

/**
 * Reserved Words for ES5 in strict mode.
 *
 * @type {KeywordsHash}
 */
KEYWORDS['5-strict'] = _hash(
    KEYWORDS['5'],
    // FutureReservedWord, strict mode. http://es5.github.io/#x7.6.1.2
    'implements let     private   public yield',
    'interface  package protected static'
);

/**
 * Reserved Words for ES6.
 *
 * 11.6.2
 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-reserved-words
 *
 * @type {KeywordsHash}
 */
KEYWORDS['6'] = _hash(
    // Keywords, ES6 11.6.2.1, http://www.ecma-international.org/ecma-262/6.0/index.html#sec-keywords
    'break    do       in         typeof',
    'case     else     instanceof var',
    'catch    export   new        void',
    'class    extends  return     while',
    'const    finally  super      with',
    'continue for      switch     yield',
    'debugger function this',
    'default  if       throw',
    'delete   import   try',
    // Future Reserved Words, ES6 11.6.2.2
    // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-future-reserved-words
    'enum await',
    // NullLiteral & BooleanLiteral
    'null true false'
);

/**
 * Reserved Words for ES6 in strict mode.
 *
 * @type {KeywordsHash}
 */
KEYWORDS['6-strict'] = _hash(
    KEYWORDS['6'],
    // Keywords, ES6 11.6.2.1
    'let static',
    // Future Reserved Words, ES6 11.6.2.2
    'implements package protected',
    'interface private public'
);

/**
 * Generates hash from strings
 *
 * @private
 * @param {...String|KeywordsHash} keywords - Space-delimited string or previous result of _hash
 * @return {KeywordsHash} - Object with keywords in keys and true in values
 */
function _hash() {
    var set = Array.prototype.map.call(Array.from(arguments), function(v) {
        return typeof v === 'string' ? v : Object.keys(v).join(' ');
    }).join(' ');

    return set.split(/\s+/)
        .reduce(function(res, keyword) {
            res[keyword] = true;
            return res;
        }, {});
}

},{"assert":4}],12:[function(require,module,exports){
module.exports = function isBuffer(arg) {
  return arg && typeof arg === 'object'
    && typeof arg.copy === 'function'
    && typeof arg.fill === 'function'
    && typeof arg.readUInt8 === 'function';
}
},{}],13:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
  if (!isString(f)) {
    var objects = [];
    for (var i = 0; i < arguments.length; i++) {
      objects.push(inspect(arguments[i]));
    }
    return objects.join(' ');
  }

  var i = 1;
  var args = arguments;
  var len = args.length;
  var str = String(f).replace(formatRegExp, function(x) {
    if (x === '%%') return '%';
    if (i >= len) return x;
    switch (x) {
      case '%s': return String(args[i++]);
      case '%d': return Number(args[i++]);
      case '%j':
        try {
          return JSON.stringify(args[i++]);
        } catch (_) {
          return '[Circular]';
        }
      default:
        return x;
    }
  });
  for (var x = args[i]; i < len; x = args[++i]) {
    if (isNull(x) || !isObject(x)) {
      str += ' ' + x;
    } else {
      str += ' ' + inspect(x);
    }
  }
  return str;
};


// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
  // Allow for deprecating things in the process of starting up.
  if (isUndefined(global.process)) {
    return function() {
      return exports.deprecate(fn, msg).apply(this, arguments);
    };
  }

  if (process.noDeprecation === true) {
    return fn;
  }

  var warned = false;
  function deprecated() {
    if (!warned) {
      if (process.throwDeprecation) {
        throw new Error(msg);
      } else if (process.traceDeprecation) {
        console.trace(msg);
      } else {
        console.error(msg);
      }
      warned = true;
    }
    return fn.apply(this, arguments);
  }

  return deprecated;
};


var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
  if (isUndefined(debugEnviron))
    debugEnviron = process.env.NODE_DEBUG || '';
  set = set.toUpperCase();
  if (!debugs[set]) {
    if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
      var pid = process.pid;
      debugs[set] = function() {
        var msg = exports.format.apply(exports, arguments);
        console.error('%s %d: %s', set, pid, msg);
      };
    } else {
      debugs[set] = function() {};
    }
  }
  return debugs[set];
};


/**
 * Echos the value of a value. Trys to print the value out
 * in the best way possible given the different types.
 *
 * @param {Object} obj The object to print out.
 * @param {Object} opts Optional options object that alters the output.
 */
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
  // default options
  var ctx = {
    seen: [],
    stylize: stylizeNoColor
  };
  // legacy...
  if (arguments.length >= 3) ctx.depth = arguments[2];
  if (arguments.length >= 4) ctx.colors = arguments[3];
  if (isBoolean(opts)) {
    // legacy...
    ctx.showHidden = opts;
  } else if (opts) {
    // got an "options" object
    exports._extend(ctx, opts);
  }
  // set default options
  if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
  if (isUndefined(ctx.depth)) ctx.depth = 2;
  if (isUndefined(ctx.colors)) ctx.colors = false;
  if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
  if (ctx.colors) ctx.stylize = stylizeWithColor;
  return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;


// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
  'bold' : [1, 22],
  'italic' : [3, 23],
  'underline' : [4, 24],
  'inverse' : [7, 27],
  'white' : [37, 39],
  'grey' : [90, 39],
  'black' : [30, 39],
  'blue' : [34, 39],
  'cyan' : [36, 39],
  'green' : [32, 39],
  'magenta' : [35, 39],
  'red' : [31, 39],
  'yellow' : [33, 39]
};

// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
  'special': 'cyan',
  'number': 'yellow',
  'boolean': 'yellow',
  'undefined': 'grey',
  'null': 'bold',
  'string': 'green',
  'date': 'magenta',
  // "name": intentionally not styling
  'regexp': 'red'
};


function stylizeWithColor(str, styleType) {
  var style = inspect.styles[styleType];

  if (style) {
    return '\u001b[' + inspect.colors[style][0] + 'm' + str +
           '\u001b[' + inspect.colors[style][1] + 'm';
  } else {
    return str;
  }
}


function stylizeNoColor(str, styleType) {
  return str;
}


function arrayToHash(array) {
  var hash = {};

  array.forEach(function(val, idx) {
    hash[val] = true;
  });

  return hash;
}


function formatValue(ctx, value, recurseTimes) {
  // Provide a hook for user-specified inspect functions.
  // Check that value is an object with an inspect function on it
  if (ctx.customInspect &&
      value &&
      isFunction(value.inspect) &&
      // Filter out the util module, it's inspect function is special
      value.inspect !== exports.inspect &&
      // Also filter out any prototype objects using the circular check.
      !(value.constructor && value.constructor.prototype === value)) {
    var ret = value.inspect(recurseTimes, ctx);
    if (!isString(ret)) {
      ret = formatValue(ctx, ret, recurseTimes);
    }
    return ret;
  }

  // Primitive types cannot have properties
  var primitive = formatPrimitive(ctx, value);
  if (primitive) {
    return primitive;
  }

  // Look up the keys of the object.
  var keys = Object.keys(value);
  var visibleKeys = arrayToHash(keys);

  if (ctx.showHidden) {
    keys = Object.getOwnPropertyNames(value);
  }

  // IE doesn't make error fields non-enumerable
  // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
  if (isError(value)
      && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
    return formatError(value);
  }

  // Some type of object without properties can be shortcutted.
  if (keys.length === 0) {
    if (isFunction(value)) {
      var name = value.name ? ': ' + value.name : '';
      return ctx.stylize('[Function' + name + ']', 'special');
    }
    if (isRegExp(value)) {
      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
    }
    if (isDate(value)) {
      return ctx.stylize(Date.prototype.toString.call(value), 'date');
    }
    if (isError(value)) {
      return formatError(value);
    }
  }

  var base = '', array = false, braces = ['{', '}'];

  // Make Array say that they are Array
  if (isArray(value)) {
    array = true;
    braces = ['[', ']'];
  }

  // Make functions say that they are functions
  if (isFunction(value)) {
    var n = value.name ? ': ' + value.name : '';
    base = ' [Function' + n + ']';
  }

  // Make RegExps say that they are RegExps
  if (isRegExp(value)) {
    base = ' ' + RegExp.prototype.toString.call(value);
  }

  // Make dates with properties first say the date
  if (isDate(value)) {
    base = ' ' + Date.prototype.toUTCString.call(value);
  }

  // Make error with message first say the error
  if (isError(value)) {
    base = ' ' + formatError(value);
  }

  if (keys.length === 0 && (!array || value.length == 0)) {
    return braces[0] + base + braces[1];
  }

  if (recurseTimes < 0) {
    if (isRegExp(value)) {
      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
    } else {
      return ctx.stylize('[Object]', 'special');
    }
  }

  ctx.seen.push(value);

  var output;
  if (array) {
    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
  } else {
    output = keys.map(function(key) {
      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
    });
  }

  ctx.seen.pop();

  return reduceToSingleString(output, base, braces);
}


function formatPrimitive(ctx, value) {
  if (isUndefined(value))
    return ctx.stylize('undefined', 'undefined');
  if (isString(value)) {
    var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                                             .replace(/'/g, "\\'")
                                             .replace(/\\"/g, '"') + '\'';
    return ctx.stylize(simple, 'string');
  }
  if (isNumber(value))
    return ctx.stylize('' + value, 'number');
  if (isBoolean(value))
    return ctx.stylize('' + value, 'boolean');
  // For some reason typeof null is "object", so special case here.
  if (isNull(value))
    return ctx.stylize('null', 'null');
}


function formatError(value) {
  return '[' + Error.prototype.toString.call(value) + ']';
}


function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
  var output = [];
  for (var i = 0, l = value.length; i < l; ++i) {
    if (hasOwnProperty(value, String(i))) {
      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
          String(i), true));
    } else {
      output.push('');
    }
  }
  keys.forEach(function(key) {
    if (!key.match(/^\d+$/)) {
      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
          key, true));
    }
  });
  return output;
}


function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
  var name, str, desc;
  desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
  if (desc.get) {
    if (desc.set) {
      str = ctx.stylize('[Getter/Setter]', 'special');
    } else {
      str = ctx.stylize('[Getter]', 'special');
    }
  } else {
    if (desc.set) {
      str = ctx.stylize('[Setter]', 'special');
    }
  }
  if (!hasOwnProperty(visibleKeys, key)) {
    name = '[' + key + ']';
  }
  if (!str) {
    if (ctx.seen.indexOf(desc.value) < 0) {
      if (isNull(recurseTimes)) {
        str = formatValue(ctx, desc.value, null);
      } else {
        str = formatValue(ctx, desc.value, recurseTimes - 1);
      }
      if (str.indexOf('\n') > -1) {
        if (array) {
          str = str.split('\n').map(function(line) {
            return '  ' + line;
          }).join('\n').substr(2);
        } else {
          str = '\n' + str.split('\n').map(function(line) {
            return '   ' + line;
          }).join('\n');
        }
      }
    } else {
      str = ctx.stylize('[Circular]', 'special');
    }
  }
  if (isUndefined(name)) {
    if (array && key.match(/^\d+$/)) {
      return str;
    }
    name = JSON.stringify('' + key);
    if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
      name = name.substr(1, name.length - 2);
      name = ctx.stylize(name, 'name');
    } else {
      name = name.replace(/'/g, "\\'")
                 .replace(/\\"/g, '"')
                 .replace(/(^"|"$)/g, "'");
      name = ctx.stylize(name, 'string');
    }
  }

  return name + ': ' + str;
}


function reduceToSingleString(output, base, braces) {
  var numLinesEst = 0;
  var length = output.reduce(function(prev, cur) {
    numLinesEst++;
    if (cur.indexOf('\n') >= 0) numLinesEst++;
    return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
  }, 0);

  if (length > 60) {
    return braces[0] +
           (base === '' ? '' : base + '\n ') +
           ' ' +
           output.join(',\n  ') +
           ' ' +
           braces[1];
  }

  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}


// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
  return Array.isArray(ar);
}
exports.isArray = isArray;

function isBoolean(arg) {
  return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;

function isNull(arg) {
  return arg === null;
}
exports.isNull = isNull;

function isNullOrUndefined(arg) {
  return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;

function isNumber(arg) {
  return typeof arg === 'number';
}
exports.isNumber = isNumber;

function isString(arg) {
  return typeof arg === 'string';
}
exports.isString = isString;

function isSymbol(arg) {
  return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;

function isUndefined(arg) {
  return arg === void 0;
}
exports.isUndefined = isUndefined;

function isRegExp(re) {
  return isObject(re) && objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;

function isObject(arg) {
  return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;

function isDate(d) {
  return isObject(d) && objectToString(d) === '[object Date]';
}
exports.isDate = isDate;

function isError(e) {
  return isObject(e) &&
      (objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;

function isFunction(arg) {
  return typeof arg === 'function';
}
exports.isFunction = isFunction;

function isPrimitive(arg) {
  return arg === null ||
         typeof arg === 'boolean' ||
         typeof arg === 'number' ||
         typeof arg === 'string' ||
         typeof arg === 'symbol' ||  // ES6 symbol
         typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;

exports.isBuffer = require('./support/isBuffer');

function objectToString(o) {
  return Object.prototype.toString.call(o);
}


function pad(n) {
  return n < 10 ? '0' + n.toString(10) : n.toString(10);
}


var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
              'Oct', 'Nov', 'Dec'];

// 26 Feb 16:19:34
function timestamp() {
  var d = new Date();
  var time = [pad(d.getHours()),
              pad(d.getMinutes()),
              pad(d.getSeconds())].join(':');
  return [d.getDate(), months[d.getMonth()], time].join(' ');
}


// log is just a thin wrapper to console.log that prepends a timestamp
exports.log = function() {
  console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
};


/**
 * Inherit the prototype methods from one constructor into another.
 *
 * The Function.prototype.inherits from lang.js rewritten as a standalone
 * function (not on Function.prototype). NOTE: If this file is to be loaded
 * during bootstrapping this function needs to be rewritten using some native
 * functions as prototype setup using normal JavaScript does not work as
 * expected during bootstrapping (see mirror.js in r114903).
 *
 * @param {function} ctor Constructor function which needs to inherit the
 *     prototype.
 * @param {function} superCtor Constructor function to inherit prototype from.
 */
exports.inherits = require('inherits');

exports._extend = function(origin, add) {
  // Don't do anything if add isn't an object
  if (!add || !isObject(add)) return origin;

  var keys = Object.keys(add);
  var i = keys.length;
  while (i--) {
    origin[keys[i]] = add[keys[i]];
  }
  return origin;
};

function hasOwnProperty(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}

}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./support/isBuffer":12,"_process":9,"inherits":5}]},{},[2])(2)
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloParamsJS
 * Classe wrapper dei parametri di configurazione di Tolomeo
 *
 * @constructor
 * 
 * 
 * @param {Object} config
 * 
 * 
 */
function ToloParamsJS(config){
	if(config && typeof config == 'object'){
        for(var p in config){
            this[p] = config[p];
        }
        this.createMapDefinition();
    }
	
}

ToloParamsJS.enhanceEffects = [{ getName: function(){ return ToloI18n.getMsg("ToloParamsJS.effectbrightness");}, key: 'effectbrightness', cssProp: 'brightness', cssUm:'', defaultValue: 1, minValue: 0, maxValue: 3, scale: 100},
                      { getName: function(){ return ToloI18n.getMsg("ToloParamsJS.effectcontrast");}, key: 'effectcontrast', cssProp: 'contrast', cssUm:'', defaultValue: 1, minValue: 0, maxValue: 3, scale: 100},
                      { getName: function(){ return ToloI18n.getMsg("ToloParamsJS.effectsaturate");}, key: 'effectsaturate', cssProp: 'saturate', cssUm:'', defaultValue: 1, minValue: 0, maxValue: 3, scale: 100},
                      { getName: function(){ return ToloI18n.getMsg("ToloParamsJS.effectblur");}, key: 'effectblur', cssProp: 'blur', cssUm:'px', defaultValue: 0, minValue: 0, maxValue: 10, scale: 1},
                      { getName: function(){ return ToloI18n.getMsg("ToloParamsJS.effectsepia");}, key: 'effectsepia', cssProp: 'sepia', cssUm:'', defaultValue: 0, minValue: 0, maxValue: 1, scale: 100},
                      { getName: function(){ return ToloI18n.getMsg("ToloParamsJS.effectinvert");}, key: 'effectinvert', cssProp: 'invert', cssUm:'', defaultValue: 0, minValue: 0, maxValue: 1, scale: 100},
                      { getName: function(){ return ToloI18n.getMsg("ToloParamsJS.effectgrayscale");}, key: 'effectgrayscale', cssProp: 'grayscale', cssUm:'', defaultValue: 0, minValue: 0, maxValue: 1, scale: 100}];


/**
 * @method getSelectableCodTPN
 * Restituisce la lista dei codiciTPN dei layer che risultano selezionabili.
 * 
 * @param {Boolean} forceRefresh
 * 
 * 
 * @return {Array}
 * Lista dei codiciTPN dei layer che risultano selezionabili
 * 
 */
ToloParamsJS.prototype.getSelectableCodTPN = function (forceRefresh) {
	if(forceRefresh || !this.selectableCodTPN){		
		this.selectableCodTPN = [];
		if (!!this.azioniApertura.modoEditingSingolo)  {
			this.selectableCodTPN.push(this.azioniApertura.modoEditingSingolo.layerCODTPN);	
		} else {
			for(var index=0; index<this.azioniEventi.eventiLayerList.length; index++) {
				var evl = this.azioniEventi.eventiLayerList[index];
				if (evl.interactable) {
					this.selectableCodTPN.push(evl.codTPN);
				}
			}
		}
	}
	return this.selectableCodTPN;
}

/**
 * @method isSelectable
 * Restituisce true sel il codTPN passato è quello di uno dei layer
 * 
 * @param {Number} codTPN
 * 
 * 
 * @return {Boolean}
 * 
 * 
 */
ToloParamsJS.prototype.isSelectable = function (codTPN) {	
	var selectableCodTPN = this.getSelectableCodTPN();
	for(var i=0; i < selectableCodTPN.length; i++){
		if(selectableCodTPN[i]==codTPN) return true;
	}
	return false;
}

/**
 * @method getParamJSLayer
 * 
 * 
 * @param {Number} codTPN
 * 
 * 
 * @return {Object}
 * I parametri JS del layer.
 * 
 */
ToloParamsJS.prototype.getParamJSLayer = function (codTPN) {
	var evl = null;	
	for(var index=0; index<this.azioniEventi.eventiLayerList.length; index++) {
		evl = this.azioniEventi.eventiLayerList[index];
		if (evl.codTPN==codTPN) {
			return evl;
		}
	}
	return null;
}

/**
 * @method getLayerSfondoString
 * Ritorna una stringa contenente l'elenco dei nomi dei layer di sfondo separati da saparator
 * 
 * @param {Object} mappaCurr
 * oggetto mappa corrente
 * 
 * @param {String} separator
 * separatore
 * 
 * @return {String}
 * Ritorna una stringa contenente l'elenco dei nomi dei layer di sfondo separati da separator oppure null nel caso non ci sia nessun layer 
 * 
 */
ToloParamsJS.prototype.getLayerSfondoString = function(mappaCurr, separator) {
	var laystr = null;
	
	// Inserimento livelli predefiniti di sfondo
	if(mappaCurr.sfondo != null) {
		for (var j = 0; j < mappaCurr.sfondo.layerSfondoList.length; j++) {	
			var layerSfondo = mappaCurr.sfondo.layerSfondoList[j];
			if (laystr==null) laystr = '';
			laystr += (j!=0) ? separator : '';
			// Prendo il layer di sfondo corrente
			laystr += layerSfondo.name ;
		}
	}
	
	return laystr;
}

/**
 * @method getLayerSfondoStyleString
 * Ritorna una stringa contenente l'elenco degli stili dei layer di sfondo separati da saparator. Se uno stile non è definito comunque viene inserita una stringa vuota per indicare la necessità di utilizzare lo stile di default
 * Se non presenti layer di cui definire gli stili ritorna null
 * 
 * @param {Object} mappaCurr
 * oggetto mappa corrente
 * 
 * @param {String} separator
 * separatore
 *
 * @return {String}
 * Ritorna una stringa contenente l'elenco dei nomi dei layer di sfondo separati da saparator 
 * 
 */
ToloParamsJS.prototype.getLayerSfondoStyleString = function(mappaCurr, separator) {
	var laystr = null;
	
	// Inserimento livelli predefiniti di sfondo
	if(mappaCurr.sfondo != null) {
		for (var j = 0; j < mappaCurr.sfondo.layerSfondoList.length; j++) {	
			var layerSfondo = mappaCurr.sfondo.layerSfondoList[j];
			if (laystr==null) laystr = '';
			laystr += (j!=0) ? separator : '';
			// Prendo il layer di sfondo corrente
			laystr += (layerSfondo.stile ? layerSfondo.stile : '') ;
		}
	}
	
	return laystr;
}

/**
 * @method onEachLegendaCategory
 * Metodo per il lancio della funzione fn all'interno del contesto scope per ogni categoria  
 * Il metodo agisce in maniera ricorsiva se bRecurce non è definito o è true 
 * 
 * @param {Object} categ
 * 
 * 
 * @param {Function} fn
 * 
 * 
 * @param {Object} scope
 * 
 * 
 * @param {Boolean} bRecurse
 * 
 * 
 */
ToloParamsJS.prototype.onEachLegendaCategory= function(categ, fn, scope, bRecurse ) {
	var scopebuff = (scope) ? scope : this;
	var bRecurse = (bRecurse!=undefined && bRecurse !=null) ?  bRecurse : true;
	
	// Prima nelle categorie annidate perchè a meno di cambio ordine sono mostrate prima
	if (bRecurse && categ.categoryList) {
		for (var i=0; i<categ.categoryList.length; i++) {
			this.onEachLegendaCategory(categ.categoryList[i], fn, scope, bRecurse);
		}
	}
	
	// poi eseguo su questa categoria
	fn.call(scope, categ);
}

/**
 * @method getServer
 * 
 * 
 * @param {String} id
 * 
 * 
 * @param {Object} mappa
 * 
 * 
 * @return {Object}
 * 
 * 
 */
ToloParamsJS.prototype.getServer= function(id, mappa) {
	
	if (!id || id=="INLINESERVERID") {
	
		id = "INLINESERVERID";
		var server0 = new toloServerMappe();
		server0.nome 					= mappa.nome;
		server0.typeDescription       	= mappa.typeDescription;
		server0.typeCode             	= mappa.typeCode;
		server0.nomeCredenziale   		= mappa.nomeCredenziale;
		server0.allowServerConnection 	= mappa.allowServerConnection;
		server0.url          		  	= mappa.url;
		server0.serverOpts				= mappa.mapOptions;
		server0.tilesMultiple			= mappa.tilesMultiple;		
		server0.noTolomeoParams			= false;
		
		server0.tileStampaLarghezza		= (server0.tileStampaLarghezza ? inlineServerInfo.tileStampaLarghezza : 0);
		server0.tileStampaAltezza		= (server0.tileStampaAltezza ? inlineServerInfo.tileStampaAltezza : 0);									
		
		return server0;
	} else {
	
	
		if (this.serverPool!=undefined && this.serverPool!=null) {
			var listaServer = this.serverPool.serverList;
			
			for (var i=0; i<listaServer.length; i++ ) {
				if (listaServer[i].id==id) return new toloServerMappe(listaServer[i]);
			}
		}
	}
	return null;
	
}

/**
 * @method getLegendaCategory
 * Metodo privato per lo scorrimento ricorsivo delle categorie
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {String} idxs
 * 
 * 
 * @param {Object} baseCat
 * 
 * 
 * @return {Object}
 * 
 * 
 */
ToloParamsJS.prototype.getLegendaCategory=function(nMappa, idxs, baseCat) {
	
	var base = (baseCat==undefined || baseCat==null) ? this.mappe.mappaList[nMappa].legenda : baseCat;
	var idxArray;
	if (typeof idxs === "string") {
		idxArray=idxs.split("/");
	} else {
		// Copio per non modificare il valore passato
		idxArray=idxs.concat([]);
	}
	if (idxArray.length==1) return base.categoryList[idxArray[0]];
	else {
		var idx = idxArray.shift();
		return this.getLegendaCategory(nMappa, idxArray, base.categoryList[idx]);		
	}
}

/**
 * @method getLegendaParentCategoryIdx
 * Metodo per ottenere l'indice della categoria padre 
 * 
 * @param {String} catIdx
 * 
 * 
 * @return {Object}
 * 
 * 
 */
ToloParamsJS.prototype.getLegendaParentCategoryIdx=function(catIdx) {
	
	if (typeof catIdx === "string") {
		var idxs = catIdx.split("/");
		if (idxs.length<=1) return "";
		return idxs.slice(0,idxs.length-1);	
	} else {
		if (catIdx.length<=1) return "";
		return catIdx.slice(0,catIdx.length-1);
	}
	
}

/**
 * @method onEachLegendaParentCategory
 * 
 * 
 * @param {Function} fn
 * 
 * 
 * @param {Object} scope
 * 
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {String} startCatIdx
 * 
 * 
 */
ToloParamsJS.prototype.onEachLegendaParentCategory=function(fn, scope, nMappa, startCatIdx) {
	
	var parentIdx = this.getLegendaParentCategoryIdx(startCatIdx);
	while (parentIdx!="") {
		var cat = this.getLegendaCategory(nMappa, parentIdx);
		fn.call(scope, cat, parentIdx);
		parentIdx = this.getLegendaParentCategoryIdx(parentIdx);
	}
	
}

/**
 * @method areAllLegendaParentCatDefaultCategory
 * Metodo che verifica se tutte le categorie padre hanno il flag defaultCategory==true
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {String} catIdx
 * 
 * 
 * @return {Boolean}
 * 
 * 
 */
ToloParamsJS.prototype.areAllLegendaParentCatDefaultCategory=function(nMappa, catIdx) {
	var retObj1 = { bAllChecked: true };
	this.onEachLegendaParentCategory(
			function(parentCat, parentCatIdx) {
				if (!parentCat.defaultCategory) this.bAllChecked = false;
			}, 
			retObj1,
			nMappa,
			catIdx
	);
	return retObj1.bAllChecked;
}

/**
 * @method onEachCategoryOrLayerOrder
 * Scorre tutto il tag legenda della mappa nMappa a partire da:
 * - categ se tocInfo non è definito o nullo o ha layerOrder.length=0
 * - se tocInfo è definito e non nullo tutto tocInfo.layerOrder ignorando categ
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {Object} categ
 * 
 * 
 * @param {Function} fn
 * 
 * 
 * @param {Object} scope
 * 
 * 
 * @param {Boolean} bRecurse
 * 
 * 
 * @param {Object} tocInfo
 * 
 * 
 * @param {Array} filterItemType
 * 
 * 
 */
ToloParamsJS.prototype.onEachCategoryOrLayerOrder=function(nMappa, categ, fn, scope, bRecurse, tocInfo, filterItemType ) {
	
	var withFilter = (filterItemType &&  filterItemType.length>0); 
	
	if (tocInfo!=undefined && tocInfo!=null && tocInfo.layerOrder && tocInfo.layerOrder.length>0) {
		for (var i = 0; i < tocInfo.layerOrder.length; i++) {
			var laypos = tocInfo.layerOrder[i];
			var catInfo = tocInfo.getCategoryInfo(laypos.cat);
			var layInfo = catInfo.layers[laypos.lay];
			var cat = this.getLegendaCategory(nMappa, layInfo.catTreeIdx);
			var lay = cat.layerList[layInfo.layTreeIdx];
			if (!withFilter || Ext.Array.contains(filterItemType, lay.itemType)) {
				fn.call(scope, cat, lay, catInfo, layInfo);
			}
		}
	} else {
		this.onEachLegendaCategory(categ, 
				function(categ) {
					if (categ.layerList!=undefined) {
						var catInfo = null;
						if (tocInfo) {
							catInfo = tocInfo.getCategoryInfo(categ.catTreeIdx);
						}
						
						for (var i=0; i<categ.layerList.length; i++) {
							var layInfo = null;
							var layer = categ.layerList[i];
							if (catInfo) layInfo = catInfo.layers[layer.layTreeIdx];
							if (!withFilter || Ext.Array.contains(filterItemType, layer.itemType)) {
								fn.call(scope, categ, layer, catInfo, layInfo);
							}
							
						}
					}
				},
				scope, bRecurse);	
	}
	
}

/**
 * @method createMapDefinition
 * 
 * 
 * @param {Object} tocInfo
 * 
 * 
 */
ToloParamsJS.prototype.createMapDefinition = function(tocInfo) {

	var aggregationAttributes = ['serverID','opacity'];
	
	// Aggiunge tutti i filtri all'elenco degli attributi che provocano la rottura
	for (var i=0; i<ToloParamsJS.enhanceEffects.length; i++ ){
		aggregationAttributes.push(ToloParamsJS.enhanceEffects[i].key);
	}
	
	var prevAttributeValue = {};
	var prevAttributeValueInTocInfo = {};
	this.mapDefinitions = [];	
	
	for (var nMappa=0; nMappa<this.mappe.mappaList.length; nMappa++) {
		
		var mappa = this.mappe.mappaList[nMappa];
		var mapDefinition = new TolomeoExt.ToloMapDefinition();
	
		/*
		var server0 = new toloServerMappe();
		server0.nome 					= mappa.nome;
		server0.typeDescription       	= mappa.typeDescription;
		server0.typeCode             	= mappa.typeCode;
		server0.nomeCredenziale   		= mappa.nomeCredenziale;
		server0.allowServerConnection 	= mappa.allowServerConnection;
		server0.url          		  	= mappa.url;
		server0.serverOpts				= mappa.mapOptions;
		server0.tilesMultiple			= mappa.tilesMultiple;		
		server0.noTolomeoParams			= false;
		*/
		
		//inlineServerInfo = this.getServer("INLINESERVERID");
		server0 = this.getServer("INLINESERVERID", mappa);
		
		/*
		if (inlineServerInfo) {
			server0.tileStampaLarghezza		= inlineServerInfo.tileStampaLarghezza;
			server0.tileStampaAltezza		= inlineServerInfo.tileStampaAltezza;									
		
		} else {
			server0.tileStampaLarghezza		= 0;
			server0.tileStampaAltezza		= 0;			
		}*/								
		
		var idServerPrev = "";
		var layViewAggCurr = null;
		var bPrecCompleto = false;
	
		this.onEachCategoryOrLayerOrder(nMappa, mappa.legenda, 
		
				function(categ, layer, catInfo, layInfo) {
					
							var breakingTime = false;
							// Verifico il breaking time ovvero se è il momento di passare ad una nuova aggregatio perchè è 
							// cambiato un qualche attributo che la identifica.
							for(var i in aggregationAttributes){
								var attrName = aggregationAttributes[i];
								if(layer[attrName] != prevAttributeValue[attrName] ){									
									breakingTime = true;
								}
								prevAttributeValue[attrName] = layer[attrName]; 
							}
							
							// Rottura anche se il gruppo precedente è stato stabilito di essere "completo"
							if (bPrecCompleto) {
								breakingTime = true;
								bPrecCompleto = false;
							}
							
							//ALE DA RIPETERE IN SFONDO?
							// Se definita TOCInfo
							if (tocInfo) {
								//Rottura anche quando opacity settata da utente su legenda != 1
								if (layInfo['opacity']!=undefined && layInfo['opacity']!=null && layInfo['opacity']!=1) {
									breakingTime = true;
									bPrecCompleto = true;
								} else {
									// Rottura anche se valori diversi da default per qualcuno dei filtri
									for (var i=0; i<ToloParamsJS.enhanceEffects.length; i++ ){
										var effect = ToloParamsJS.enhanceEffects[i];
										if (layInfo[effect.key]!=undefined && layInfo[effect.key]!=null && layInfo[effect.key]!=effect.defaultValue) {
											breakingTime = true;
											bPrecCompleto = true;
											break;
										}
									}
								} 
							}
							
							if (layViewAggCurr==null || breakingTime) {
								
									if (layViewAggCurr!=null) mapDefinition.addLayerAggregation(layViewAggCurr);

									var defaultServer = !layer.serverID;
									var serverCurr = defaultServer ? server0 : this.getServer(layer.serverID);		
									
									var aggregationOption = {
										'tilesMultiple': serverCurr.tilesMultiple,
										'overlay': true, //mappa.overlay;
										'SRID': mappa.SRID,
										'units': mappa.units,
										'mostraInLegenda': mappa.mostraInLegenda,
										'layerOptions': mappa.viewerOptions,
										'imagetype': mappa.imagetype,
										'server': serverCurr
									};
									
									// Aggiungo alle proprietà di aggregazione quelle eventualmente definite sul layer o sul server, dando precedenza a quelle del layer 
									// Sulla Layer Aggregation mi trovero gli attributi ch ne hanno dato origine
									for(var i in aggregationAttributes){
										var attrName = aggregationAttributes[i];
										aggregationOption[attrName] = layer[attrName] || (defaultServer ? mappa[attrName] : serverCurr[attrName]);
									}	
									if (tocInfo && layInfo.opacity!=undefined && layInfo.opacity!=null) aggregationOption.opacity = layInfo.opacity; 
									
									// Aggiungo anche i valori degli effetti presi da preset (se presenti)
									for (var i=0; i<ToloParamsJS.enhanceEffects.length; i++ ){
										var effect = ToloParamsJS.enhanceEffects[i];
										
										// Se valori di tocInfo disponibili
										if (tocInfo && layInfo[effect.key]!=undefined && layInfo[effect.key]!=null) {
											aggregationOption[effect.key] = layInfo[effect.key];
										} else {
											// ..altrimenti se disponibili su preset
											if (layer[effect.key]!=undefined && layer[effect.key]!=null){
												aggregationOption[effect.key] = layer[effect.key];
											} else {
												// se non presenti nemmeno su preset utilizzo default
												aggregationOption[effect.key] = effect.defaultValue;
											}
										}
									}
									
									
									// TODO verificare attributi e se ha senso che siano qua
									// TODO forzare trasparenza o no?
									layViewAggCurr = Ext.create('TolomeoExt.ToloLayerViewerAggregation',aggregationOption);
								}
								if (layInfo) {
									var bAttivo = tocInfo.areAllParentCatChecked(categ.catTreeIdx) && catInfo.checked && layInfo.checked;
									layer.checked = bAttivo;
								} else {
									var bAttivo = this.areAllLegendaParentCatDefaultCategory(nMappa, categ.catTreeIdx) && categ.defaultCategory && layer.defaultLayer;
									layer.checked = bAttivo;
									layer.style   = layer.defaultStyle; 
								}
								layViewAggCurr.layers.push(layer);
				}, 
				this, true, tocInfo, ['layer'] );
		
		if (layViewAggCurr!=null) mapDefinition.addLayerAggregation(layViewAggCurr); // layViews.push(layViewAggCurr);
		
		// Aggiunta sfondo
		if (mappa.sfondo) {
			idServerPrev = "";
			layViewAggCurr = null;
			
			prevAttributeValue = {};					
			
			for (var nSfondo=0; nSfondo<mappa.sfondo.layerSfondoList.length; nSfondo++) {
				
				var layer = mappa.sfondo.layerSfondoList[nSfondo];
				
				var breakingTime = false;
			
				for(var i in aggregationAttributes){
					var attrName = aggregationAttributes[i];
					if(layer[attrName] != prevAttributeValue[attrName] ){									
						breakingTime = true;
					}
					prevAttributeValue[attrName] = layer[attrName]; 
				}
				
				if (bPrecCompleto) {
					breakingTime = true;
					bPrecCompleto = false;
				}
				
				if (layViewAggCurr==null || breakingTime) {
					
					if (layViewAggCurr!=null) mapDefinition.addLayerAggregation(layViewAggCurr);
					
					var serverCurr = layer.serverID ? this.getServer(layer.serverID) : server0;		
					
					var aggregationOption = {
						'tilesMultiple': serverCurr.tilesMultiple,
						'overlay': true, //mappa.overlay;
						'SRID': mappa.SRID,
						'units': mappa.units,
						'mostraInLegenda': mappa.mostraInLegenda,
						'layerOptions': mappa.viewerOptions,
						'imagetype': mappa.imagetype,
						'server': serverCurr//,
					};
					
					// Aggiungo alle proprietà di aggregazione quelle eventualmente definite sul layer o sul server, dando precedenza a quelle del layer 
					// Sulla Layer Aggregation mi trovero gli attributi ch ne hanno dato origine
					for(var i in aggregationAttributes){
						var attrName = aggregationAttributes[i];
						aggregationOption[attrName] = layer[attrName] || serverCurr[attrName];
					}										
									
					// TODO verificare attributi e se ha senso che siano qua
					// TODO forzare trasparenza o no?
					layViewAggCurr = Ext.create( 'TolomeoExt.ToloLayerViewerAggregation', aggregationOption);
				}

				layer.checked = true;
				layViewAggCurr.layers.push(layer);
			}
			if (layViewAggCurr!=null) mapDefinition.addLayerAggregation(layViewAggCurr);
		}
		
		mapDefinition.reverseLayerAggregationsOrder();
		// metto il primo come baselayer
		//mapDefinition.getLayerAggregation(0).overlay=false;
		this.mapDefinitions.push(mapDefinition);

	}
	
},


ToloParamsJS.prototype.getLegendaLayerInfoByCodTPN = function(codTPN, nMappa, tocInfo){
	var retVal = {
			presetLayerInfo: null,
			tocInfoLayerInfo: null
	};
	var mappa = this.mappe.mappaList[nMappa];
	
	this.onEachCategoryOrLayerOrder(nMappa, mappa.legenda, 
			
			function(categ, layer, catInfo, layInfo) {
				if (layer.codTPN==codTPN){
					retVal.presetLayerInfo = layer;
					if (tocInfo){
						retVal.tocInfoLayerInfo = layInfo;	
					}	
				}
				
			}, 
			this, true, tocInfo, ['layer'] );
	
	return retVal ;
	
},

/**
 * @method updateMapDefinitionLayerCheckState
 * 
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {Object} layerInfo
 * 
 * 
 * @param {Boolean} forcedState
 * 
 * 
 * @return {Object}
 * 
 * 
 */
ToloParamsJS.prototype.updateMapDefinitionLayerCheckState = function(nMappa, layerInfo, forcedState) {
	
	var layerAggreg = this.mapDefinitions[nMappa].whichLayerAggregationContains(layerInfo.catTreeIdx, layerInfo.layTreeIdx);
	
	if (layerAggreg) {
		for (var i=0; i<layerAggreg.layers.length; i++) {
			var layer = layerAggreg.layers[i];
			if ((layer.catTreeIdx==layerInfo.catTreeIdx) && (layer.layTreeIdx==layerInfo.layTreeIdx)) {
				layer.checked = (forcedState!=undefined && forcedState!=null) ? forcedState : layerInfo.checked;
			}	
		}
	}
	return layerAggreg;
}

/**
 * @method updateMapDefinitionLayerStyle
 * 
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {Object} layerInfo
 * 
 * 
 * @param {Object} style
 * 
 * 
 */
ToloParamsJS.prototype.updateMapDefinitionLayerStyle= function(nMappa, layerInfo, style) {
	
	var layerAggreg = this.mapDefinitions[nMappa].whichLayerAggregationContains(layerInfo.catTreeIdx, layerInfo.layTreeIdx);
	
	if (layerAggreg) {
		for (var i=0; i<layerAggreg.layers.length; i++) {
			var layer = layerAggreg.layers[i];
			if ((layer.catTreeIdx==layerInfo.catTreeIdx) && (layer.layTreeIdx==layerInfo.layTreeIdx)) {
				layer.style = style;
			}	
		}
	}
	return layerAggreg;
}

/**
 * @method updateMapDefinitionLayerAttribution Aggiorna l'attribuzione di un layer  
 * 
 * @param {Number} nMappa Numero della mappa, attualmente gestita solo mappa 0
 * @param {Object} layerInfo Informazioni del layer, contenenti la nuova attribuzione
 */
ToloParamsJS.prototype.updateMapDefinitionLayerAttribution= function(nMappa, layerInfo) {
	
	var layerAggreg = this.mapDefinitions[nMappa].whichLayerAggregationContains(layerInfo.catTreeIdx, layerInfo.layTreeIdx);
	
	if (layerAggreg) {
		for (var i=0; i<layerAggreg.layers.length; i++) {
			var layer = layerAggreg.layers[i];
			if ((layer.catTreeIdx==layerInfo.catTreeIdx) && (layer.layTreeIdx==layerInfo.layTreeIdx)) {
				layer.attribution = layerInfo.attribution;
			}	
		}
	}
	return layerAggreg;
}

/**
 * @method updateMapDefinitionAttributions Aggiorna le attribuzioni.  
 * 
 * @param {Number} nMappa Numero della mappa, attualmente gestita solo mappa 0
 * @param {Object} tocInfo Informazioni legenda, contenenti le nuove attribuzione
 */
ToloParamsJS.prototype.updateMapDefinitionAttributions= function(nMappa, tocInfo) {
	
	for (var i=0; i<this.mapDefinitions[nMappa].getLayerAggregationCount(); i++) {
		var layerAggreg = this.mapDefinitions[nMappa].getLayerAggregation(i);
		for (var j=0; j < layerAggreg.layers.length; j++) {
			var layer = layerAggreg.layers[j];
			// Controllo se definita posizione in legenda per evitare errori con in layer di sfondo
			if (layer.catTreeIdx!=undefined && layer.layTreeIdx ) {
				var layerInfo = tocInfo.getCategoryInfo(layer.catTreeIdx).layers[layer.layTreeIdx];
				layer.attribution = layerInfo.attribution;	
			}
		}
	}
	
}

/**
 * @method updateMapDefinitionCategoryCheckState
 * 
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {Object} tocInfo
 * 
 * 
 * @param {Object} catInfo
 * 
 * 
 */
ToloParamsJS.prototype.updateMapDefinitionCategoryCheckState= function(nMappa, tocInfo, catInfo) {
	var retVal = [];
	
	if (tocInfo.layerOrder && tocInfo.layerOrder.length>0) {
		for (var i = 0; i < tocInfo.layerOrder.length; i++) {
			var laypos = tocInfo.layerOrder[i];
			var cat = tocInfo.getCategoryInfo(laypos.cat);
			var lay = cat.layers[laypos.lay];
			if (lay.itemType=='layer') {
				var bAttivo = tocInfo.areAllParentCatChecked(laypos.cat) && 
							cat.checked && lay.checked;
			
				var layAggr = this.updateMapDefinitionLayerCheckState(nMappa, lay, bAttivo);
				if (retVal.indexOf(layAggr)==-1) retVal.push(layAggr);
			}
			
		}
	} else {
		tocInfo.onEachLayer(
				function (cat,lay,catIdx,layIdx) {
					if (lay.itemType=='layer') {
						var bAttivo = tocInfo.areAllParentCatChecked(catIdx) && cat.checked && lay.checked;
						var layAggr = this.updateMapDefinitionLayerCheckState(nMappa, lay, bAttivo);
						if (retVal.indexOf(layAggr)==-1) retVal.push(layAggr);
					}
				},
				this,
				catInfo.catTreeIdx,
				true
			);
	}
	return retVal;
}

/**
 * @method getLayerAggregLayersAndStylesStrings
 * 
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {Number} layerAggregIndex
 * 
 * 
 * @param {String} sep
 * 
 * 
 * @param {Number} actualZoom
 * 
 * 
 */
ToloParamsJS.prototype.getLayerAggregLayersAndStylesStrings=function(nMappa, layerAggregIndex, sep, actualZoom) {
	
	var layers = "";
	var stili = "";
	var attribution = [];
	var layerAggreg = this.mapDefinitions[nMappa].getLayerAggregation(layerAggregIndex);
	var count = layerAggreg.layers.length-1;
	for (var j=0; j<layerAggreg.layers.length; j++) {
		var i = count-j;
		if ((layerAggreg.layers[i].checked)) {
			
			// Verifica se il layer è presente a questo livello di zoom
			var visActual = (actualZoom==undefined) || (actualZoom==null) || this.checkZoomVisibility(layerAggreg.layers[i], actualZoom);
			
			if (visActual) {
				stili  += ((layers!="") ? sep : "" ) + ((layerAggreg.layers[i].style!=undefined && layerAggreg.layers[i].style!=null) ? layerAggreg.layers[i].style : "");
				if (layerAggreg.layers[i].attribution) {
					// Verifica se c'e' già
					var bFlag = true;
					for (var k = 0; k<attribution.length; k++) {
						if (attribution[k]==layerAggreg.layers[i].attribution) {
							bFlag = false;
							break;
						}
					}
					if (bFlag) attribution.push(layerAggreg.layers[i].attribution);
				}
				layers += ((layers!="") ? sep : "" ) + layerAggreg.layers[i].name;
			}
		}
	}
	
	return { layers: layers, stili: stili, attribution: attribution};
}, 

/**
 * @method checkZoomVisibility
 * 
 * 
 * @param {Object} layer
 * 
 * 
 * @param {Number} zoom
 * 
 * 
 * @return {Boolean}
 */
ToloParamsJS.prototype.checkZoomVisibility=function(layer, zoom) {
	var scalaMinima  = layer.scalaMinima;
	var scalaMassima = layer.scalaMassima;
	
	if (((scalaMinima ==undefined)||(scalaMinima ==null)||(scalaMinima ==-1)||(scalaMinima <= zoom)) &&
	    ((scalaMassima==undefined)||(scalaMassima==null)||(scalaMassima==-1)||(zoom <= scalaMassima))) {
		visible = true;
	} else {
		visible = false;
	}
	
	return visible; 
	
}

/**
 * @method addCategory
 * Aggiunge una categoria nella posizione indicata dai parametri.
 * 
 * @param {Number} nMappa
 * numero di mappa all'interno del preset
 * 
 * @param {Object} catInfo
 * Categoria da aggiungere
 * 
 * @param {String} addPointCatIdx
 * categoria prima o dopo della quale va aggiunta la roba
 * 
 * @param {Boolean} bBefore
 * indica se aggiungere prima o dopo
 * 
 */
ToloParamsJS.prototype.addCategory=function(nMappa, catInfo, addPointCatIdx, bBefore) {
		
	// Cerca addPoint
	var addPoint = this.getLegendaCategory(nMappa, addPointCatIdx);
	
	// Cerca il parent
	//TODO
	var addPointParentIdx = this.getLegendaParentCategoryIdx(addPointCatIdx);
	var addPointParent = null;
	
	// Se parent == null sono sul primo livello
	if (addPointParentIdx == "") {
		addPointParent = this.mappe.mappaList[nMappa].legenda;
	} else {
		addPointParent = this.getLegendaCategory(nMappa, addPointParentIdx);
	}
	
	var c = (addPointParent.catTreeIdx) ? addPointParent.catTreeIdx : ""; 
	
	// Calcolo la posizione di inserimento
	var idxs = addPointCatIdx.split("/");
	var pos  = parseInt(idxs[idxs.length-1]) + ((bBefore) ? 0 : 1);
	
	// Aggiorno indice cat
	catInfo.catTreeIdx = c + ((c!="") ?  "/" : "") + pos; 
	
	//Inserisco nella giusta posizione
	if (pos > 0) {
		addPointParent.categoryList.splice(pos, 0, catInfo);
	} else {
		addPointParent.categoryList.unshift(catInfo);
	}
	
	// rinumero indici
	this.updateIdxs(addPointParent, c);
	
}
	
/**
 * @method updateIdxs
 * Aggiorna tutti gli indici catTreeIdx e layTreeIdx.
 * 
 * @param {Object} cat
 * categoria dalla quale iniziare ad aggiornare gli indici
 * 
 * @param {String} newCatTreeIdx
 * nuovo valore di treeIdx
 * 
 */
ToloParamsJS.prototype.updateIdxs=function(cat, newCatTreeIdx) {
		
	if (newCatTreeIdx!="") {
		// Aggiorna questa categoria
		var oldCatTreeIdx = cat.catTreeIdx;
		cat.catTreeIdx = newCatTreeIdx;
		//this.fireEvent("catTreeIdxUpdate", cat.catId, oldCatTreeIdx, newCatTreeIdx);
	
		// Aggiorna tutti i layer
		var layArray = cat.layerList;
		if (layArray) {
			for (var i=0; i<layArray.length; i++) {
				layArray[i].catTreeIdx = newCatTreeIdx;
				// Utilizza i il nuovo catTreeIdx perchè ha già rinumerato la categoria con l'evento precedente
				//this.fireEvent("catLayIdxUpdate", layArray[i].layId, newCatTreeIdx, layArray[i].layTreeIdx, layArray[i].layTreeIdx);
			}
		}
	} 
	
	// Cicla sulle categorie figlie
	var catArray = cat.categoryList;
	if (catArray) {
		for (var i=0; i<catArray.length; i++) {
			var newPrefix = newCatTreeIdx + ((newCatTreeIdx != "") ? "/" : "") + i ;				
			this.updateIdxs(catArray[i],newPrefix);		
		}
	}
	
}
	
/**
 * @method addLayer
 * Aggiunge un layer nella posizione indicata dai parametri.
 * 
 * @param {Number} nMappa
 * numero di mappa all'interno del preset
 * 
 * @param {Object} layInfo
 * Layer da aggiungere
 * 
 * @param {String} addPointCatIdx
 * Indice della categoria nella quale viene aggiunto il layer
 * 
 * @param {String} addPointLayIdx
 * Indice layer prima o dopo del quale aggiungere il nuovo layer
 * 
 * @param {Boolean} bBefore
 * indica se aggiungere prima o dopo
 * 
 */
ToloParamsJS.prototype.addLayer=function(nMappa, layInfo, addPointCatIdx, addPointLayIdx, bBefore) {
	
	// Cerca addPoint
	var addPoint = this.getLegendaCategory(nMappa, addPointCatIdx);
	
	// Calcolo la posizione di inserimento
	if (addPointLayIdx) {
		pos = parseInt(addPointLayIdx) + ((bBefore) ? 0 : 1);
	} else { // se non è definito addPointLayIdx inserire come primo elemento della categoria
		pos = addPoint.layerList.length-1;
	}
	
	// Aggiorno indice cat
	layInfo.catTreeIdx = addPointCatIdx; 
	layInfo.layTreeIdx = "" + pos;
	
	//Inserisco nella giusta posizione
	if (pos > 0) {
		addPoint.layerList.splice(pos, 0, layInfo);
	} else {
		addPoint.layerList.unshift(layInfo);
	}
	
	// rinumero indici
	for (var i=0; i<addPoint.layerList.length; i++) {
		var l = addPoint.layerList[i];
		var oldLayTreeIdx = l.layTreeIdx
		l.layTreeIdx = i;
		//this.fireEvent("catLayIdxUpdate", l.layId, addPointCatIdx, oldLayTreeIdx, l.layTreeIdx);
	}
	
	if (layInfo.queryable) {
	
		// Aggiunta azione vis per identify
		var eventiLayer = {
			interactable: true,
			codTPN: layInfo.codTPN,
			copertura: false,
			descrizioneLayer: layInfo.descrizione, 
			interactable: true,
			nomeLayer: layInfo.descrizione,
			tipoGeometria: 3,   // ????
			azioniEventiVis: {
				autoVisOnSelect: true,
				azioneList: [{
						ajaxCall: false,
						useWMSGetFeatureInfo: true,
						target: 'pannello'
					}
				]
			},
			azioniEventiCanc: {
				azioneList: []
				},
			azioniEventiIns: {
				azioneList: []
				},
			azioniEventiUpdateGeom: {
				azioneList: []
			},
			azioniEventiUpdateAlpha: {
				azioneList: []
			}
			
		};
		
		this.azioniEventi.eventiLayerList.push(eventiLayer);
		// forza l'aggiornamento della tabella dei selezionabili
		this.getSelectableCodTPN(true);
		
	}
	
		
}

/**
 * @method addServer
 * Aggiunge un server alla lista di quelli disponibili
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {Object} serverInfo
 * 
 * 
 * @return {Object}
 * 
 * 
 */
ToloParamsJS.prototype.addServer=function(nMappa, serverInfo) {
	
	// Controlla se esiste serverPool
	if (this.serverPool!=undefined && this.serverPool!=null) {
		// Scorre la lista dei server gia' definiti per vedere se ce ne è già uno adatto
		var listaServer = this.serverPool.serverList;
		
		for (var i=0; i<listaServer.length; i++ ) {
			if (listaServer[i].url==serverInfo.url &&
				listaServer[i].typeDescription==serverInfo.typeDescription &&
				listaServer[i].typeCode==serverInfo.typeCode &&
				listaServer[i].allowServerConnection==serverInfo.allowServerConnection &&
				listaServer[i].tilesMultiple==serverInfo.tilesMultiple &&
				listaServer[i].tileStampaAltezza==serverInfo.tileStampaAltezza &&
				listaServer[i].tileStampaLarghezza==serverInfo.tileStampaLarghezza &&
				listaServer[i].opacity==serverInfo.opacity) {
					return listaServer[i].id;
			} 
		}
		// Se non c'e' genero un SERVERID
		serverInfo.id = "AUTOGENERATED" + Math.random();
		listaServer.push(serverInfo);
		return serverInfo.id;
		
	} else {
		this.serverPool = [];
		serverInfo.id = "AUTOGENERATED" + Math.random();
		listaServer.push(serverInfo);
		return serverInfo.id;
	}
	
}

/**
 * @method isQGISExportable
 * 
 * 
 * @param {Number} nMappa
 * 
 * 
 * @param {String} catTreeIdx
 * 
 * 
 * @param {String} layTreeIdx
 * 
 * 
 * @return {Boolean}
 * 
 * 
 */
ToloParamsJS.prototype.isQGISExportable=function(nMappa, catTreeIdx, layTreeIdx) {

	var mappa = this.mappe.mappaList[nMappa];
	var cat = this.getLegendaCategory(nMappa, catTreeIdx);
	var lay = cat.layerList[layTreeIdx];
	var serverID = lay.serverID;
	var server = this.getServer(serverID, mappa);
	
	return (server.typeCode=='11');
}

/**
 * @method isQueryBuilder
 *  
 * @return {Boolean}
 */
ToloParamsJS.prototype.isQueryBuilder=function() {
	var qb = 0;
	for(var i=0; i<this.azioniEventi.eventiLayerList.length; i++) {
		var eventiLayer = this.azioniEventi.eventiLayerList[i];
		if (eventiLayer.queryBuilder) {
			qb++;
			break;
		}
	}
	return (qb>0) ? true : false;
}


ToloParamsJS.prototype.withSpatialiteExporter=function(codTPN) {	
	for(var i=0; i<this.azioniEventi.eventiLayerList.length; i++) {
		var eventiLayer = this.azioniEventi.eventiLayerList[i];
		if (eventiLayer.codTPN == codTPN) {			
			if(eventiLayer.queryBuilder){
				return !!eventiLayer.queryBuilder.conEsportaSpatialite;
			} else {
				return false;
			}
		}
	}	
}

ToloParamsJS.prototype.withCodeless=function() {	
	for(var i=0; i<this.azioniEventi.eventiLayerList.length; i++) {
		var eventiLayer = this.azioniEventi.eventiLayerList[i];
		if(eventiLayer.codeless){
			return true;
		}		
	}
	return false;
}


ToloParamsJS.prototype.withViewCodeless=function() {	
	for(var i=0; i<this.azioniEventi.eventiLayerList.length; i++) {
		var eventiLayer = this.azioniEventi.eventiLayerList[i];
		if(eventiLayer.viewCodeless){
			return true;
		}		
	}
	return false;
}/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloCrossAjaxUtil
 * 
 * 
 */
TolomeoExt.ToloCrossAjaxUtil = {
	
		/**
		 * @property {Object} DEFAULT_PORTS
		 * 
		 * 
		 */
		DEFAULT_PORTS : {
			'http:' : 80,
			'https:': 443
		},

		/**
		 * @method urlIsCrossDomain
		 * 
		 * 
		 * @param {String} u
		 * 
		 * 
		 */
		urlIsCrossDomain: function(u) {
			var match = /(?:(\w*:)\/\/)?([\w\.]*)(?::(\d*))?/.exec(u);
			var protocol = match[1], hostname = match[2], port = match[3];
			
			if (!protocol) return false; // No protocol, not cross-domain
			if(protocol!=location.protocol) return true;
			
			if(!port) port = this.DEFAULT_PORTS[protocol];
			var locationPort = location.port? location.port : this.DEFAULT_PORTS[location.protocol];
			
			if(port != locationPort) return true;			
			return hostname != location.hostname;
			//return (match[1] != location.protocol) || (match[2] != location.host);
		}, 

		/**
		 * @method getProxy
		 * 
		 * 
		 * @param {String} scriptTag
		 * 
		 * 
		 * @param {String} url
		 * 
		 * 
		 * @param {String} method
		 * 
		 * 
		 */
		getProxy: function(scriptTag, url, method) {
			var proxy=null;
			var reqMethod = (method || 'POST').toUpperCase();
			
			if ((scriptTag != undefined) && (scriptTag != null)) { 
				proxy = (scriptTag) ?  Ext.create('Ext.data.proxy.JsonP',{
						url: url,
						reader: 'json'
					}) : Ext.create('Ext.data.proxy.Ajax',{ 
					api: {
						'read': url, // {'url': url,'method': reqMethod}
						actionsMethods: {read: reqMethod }
					}, 
					reader: {
						readRecordsOnFailure: false
					}
				}); 
			} else {
				proxy = (TolomeoExt.ToloCrossAjaxUtil.urlIsCrossDomain(url)) ? Ext.create('Ext.data.proxy.JsonP',{
						url: url,
						reader: 'json'
					}) : Ext.create('Ext.data.proxy.Ajax',{
					timeout: Ext.Ajax.timeout,
					api: {
						'read': url,
						actionsMethods: {read: reqMethod }
					}, 
					reader: {
						readRecordsOnFailure: false
					}
				});
			}
			return proxy;
		}

}

/**
 * @class TolomeoExt.ToloCrossAjax
 * @extends Ext.util.Observable
 * 
 * 
 */
Ext.define('TolomeoExt.ToloCrossAjax', {
	
	extend: 'Ext.util.Observable',
	
	/** 
	 * @property {Object} store
	 * 
	 * 
	 */
	store: null,
	
	/*
	urlIsCrossDomain: function(u) {
		var match = /(?:(\w*:)\/\/)?([\w\.]*(?::\d*)?)/.exec(u);
		if (!match[1]) return false; // No protocol, not cross-domain
		return (match[1] != location.protocol) || (match[2] != location.host);
	},
	*/
	
	/**
	 * @method request
	 * 
	 * 
	 * @param {Object} options
	 * opzioni della richiesta.
	 * 
	 */
	request: function(options) {
		var me= this;
		var proxy = TolomeoExt.ToloCrossAjaxUtil.getProxy(options.scriptTag, options.url, options.method);
				
		// Creazione Store 
		 this.store = new Ext.data.JsonStore({
									    // store configs
									    autoDestroy: false,
									    proxy: proxy
									});
		
		 //this.store.on('exception', this.storeException);
		 proxy.on('exception', this.storeException);
		 
		// Lettura Dati
		this.store.load({
			params: options.params,
			callback: function(records, loadOptions, success) {
									me.loadCallback(records, loadOptions, success, options);
									},
			scope: me
		});		
	},
	
	/**
	 * @method loadCallback
	 * 
	 * 
	 * @param {Object} records
	 * record caricati.
	 * 
	 * @param {Object} loadOptions
	 * opzioni di caricamento.
	 * 
	 * @param {Object} success
	 * indica se l'operazione ha avuto successo.
	 * 
	 * @param {Object} originalOptions
	 * opzioni di caricamento originali. 
	 * 
	 */
	loadCallback: function(records, loadOptions, success, originalOptions) {

		if (success) {
			originalOptions.success.call(originalOptions.scope, records, this.store, originalOptions);
		} else {
			if (originalOptions.failure) originalOptions.failure.call(originalOptions.scope, this.store, originalOptions); 
		}

	},
	
	/**
	 * @method storeException
	 * 
	 * 
	 * @param {Object} dataProxy
	 * il proxy.
	 * 
	 * @param {Object} type
	 * il tipo dell'eccezione.
	 * 
	 * @param {Object} action
	 * l'azione associata.
	 * 
	 * @param {Object} options
	 * le opzioni . 
	 * 
	 * @param {Object} response
	 * la risposta ricevuta.
	 * 
	 * @param {Object} arg
	 * gli argomenti.
	 * 
	 */
	//  Ext.data.proxy.Proxy this, Object response, Ext.data.Operation operation, Object eOpts
	//storeException: function(dataProxy, type, action, options, response, arg) {
	storeException: function(dataProxy, response, operation, eopts) {
		
		var msg = "";
		
		/*
		if (type=='remote')  {
			msg = response.responseText;
	
		} else {
			//server ok
			if (response && response.status == 200) {
				var decodedResponse = (response.responseText == undefined) ? response : Ext.decode(response.responseText);
				msg = decodedResponse.msgErrore;
				stack = decodedResponse.msgStackTrace;
			//server ko
			} else {
				msg = 'Risorsa chiamata: ' + options.url + '<br/><br/>Risposta: ' + response.status + ' ' + response.statusText;
				stack = null;
			}
		}
		*/
		//server ok
		if (response && response.status == 200) {
			var decodedResponse = (response.responseText == undefined) ? response : Ext.decode(response.responseText);
			//msg = decodedResponse.msgErrore;
			//stack = decodedResponse.msgStackTrace;
			
			msg = decodedResponse.rows[0].msgErrore;
			stack = decodedResponse.rows[0].msgStackTrace;
		//server ko
		} else {
			msg = ToloI18n.getMsg("ToloCrossAjax.ErrMsg",{ URL: operation.request.url, STATUS: response.status, STATUSTEXT: response.statusText});
			stack = null;
		}
		
		this.stackDisabled = (stack == '' || stack == undefined) ? true : false; 
		
		this.errorWin = new Ext.Window({
			title: ToloI18n.getMsg("ToloCrossAjax.winError.title"),
			layout: 'anchor',
			defaultAnchor : '0',
			//bodyStyle:'background-color:white',
			plain: true,
			border: false,
			modal: true,
			padding: 5,
			width: 500,
			autoHeight: true,
			autoScroll: true,
			buttonAlign: 'center',
			buttons: [{
				text: 'OK',
					listeners: {click: {fn: function() {
	       			this.errorWin.hide();
	       		},scope: this}}	
			}],
			items: [{
				xtype: 'box',
				html: '<div class="finestraIcona finestraIconaErrore"></div><div class="finestraIconaTesto">' + msg + '</div>',
				//bodyStyle: 'padding:5px',
				style: {
		            paddingBottom: '25px'
		        }
			},{
				xtype: 'panel',
				layout: 'fit',
				title: 'Stacktrace',
				collapsible: true,
				collapsed: true,
				titleCollapse: true,
				border: true,
				disabled: this.stackDisabled,
				items: [{
					xtype: 'textarea',
					//anchor : '0',
					hideLabel: true,
					readOnly: true,
					height: 300,
					autoScroll: true,
					style: {
						font: '11px courier new'
					},
		            value: stack
				}],
				listeners: {
					'expand' : {
						fn: function() {
							this.errorWin.setWidth(800);
							this.errorWin.center();
						},
						scope: this
					},
					'collapse' : {
						fn: function() {
							if (this.errorWin) {
								this.errorWin.setWidth(500);
								this.errorWin.center();
							}
						},
						scope: this
					}
				}
			}]
		}).show();
	},
	
	/**
	 * @method onDestroy
	 * 
	 * 
	 */
	onDestroy: function() {
		if (store) store.destroy();
		this.callParent();
	}
	
});


/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * @class TolomeoExt.ToloMeasurePanelExt
 * @extends Ext.Window
 *
 */
Ext.define('TolomeoExt.ToloMeasurePanelExt', {
	extend: 'Ext.Window',	
 
	/** 
	 * @property {Boolean} [closable=false]
	 * 
	 * 
	 */
	closable: false,

	/** 
	 * @property {Boolean} [bodyBorder=false]
	 * 
	 * 
	 */
	bodyBorder: false,

	/** 
	 * @property {Boolean} [border=false]
	 * 
	 * 
	 */
	border: false,

	/** 
	 * @property {Boolean} [frame=true]
	 * 
	 * 
	 */
	frame: true,
	
	/** 
	 * @property {Boolean} [header=false]
	 * 
	 * 
	 */
	header: false,

	/** 
	 * @property {Boolean} [resizable=false]
	 * 
	 * 
	 */
	resizable: false,

	/** 
	 * @property {Boolean} [constraint=true]
	 * 
	 * 
	 */
	constrain: true,

	/*
	 * @property {Boolean} [monitorResize=true]
	 * 
	 * 
	 */
//	monitorResize: true,

	/*
	 * @property {Number} [width=180]
	 * 
	 */
	//width: 180,

	/** 
	 * @property {String} [bodyStyle='background-color:white;padding: 2px 5px 2px 5px;']
	 * 
	 */
	bodyStyle: 'background-color:white;padding: 2px 5px 2px 5px;',

	/**
	 * @method initComponent
	 * Create a new TolomeoExt.ToloMeasurePanelExt
	 * 
	 */	
	initComponent: function() {
		
		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);

		this.callParent(arguments);
		this.doLayout();
	},
   
	/**
	 * @method showMeasure
	 * 
	 * 
	 * @param {Object} tipo
	 * tipo.
	 * 
	 */ 
	showMeasure: function (tipo) {
		this.update(ToloI18n.getMsg("ToloMeasurePanelExt.showMeasure.msg"));
		this.setVisible(true);
		this.setPosition(0,0);
		//this.toFront();		
	},

	/**
	 * @method hideMeasure
	 * 
	 * 
	 */ 
	hideMeasure: function () {
		this.setVisible(false);
	},
	
	/**
	 * @method displayMeasure
	 * 
	 * 
	 * @param {Object} measureObj
	 * Object with following properties 
	 * dimension: 1 = line, 2 = polygon
	 * length: object with "measure" and "units" properties
	 * area: object with "measure" and "units" properties
 	 */ 
	displayMeasure: function (measureObj) {
		if(measureObj.dimension == 1){
			this.update(ToloI18n.getMsg("ToloMeasurePanelExt.displayMeasure.lung", {LENGTH: Ext.util.Format.number(measureObj.length.measure,"0,000.000"), UNITS: measureObj.length.units}));
		} else {
			this.update(ToloI18n.getMsg("ToloMeasurePanelExt.displayMeasure.area", {LENGTH: Ext.util.Format.number(measureObj.length.measure,"0,000.000"),
																					 LENGTHUNITS: measureObj.length.units,
																					 AREA: Ext.util.Format.number(measureObj.area.measure,"0,000.000"),
																					 AREAUNITS: measureObj.area.units }));
		}
		this.setVisible(true);		
	},

	/**
	 * @method onMeasureEnd
	 * Chiamata quando il poligono di misura è finito
	 *
	 * @param {Object} geom
	 * geom.
	 * 
	 */ 
	onMeasureEnd: function(geom) {},

	/**
	 * @method bindToViewerPanel
	 * 
	 * 
	 * @param {Object} viewer
	 * viewer.
	 * 
	 */ 
	bindToViewerPanel: function(viewer) {
		if (viewer!=null) {
			// Registrazione in viewerPanel
			viewer.on('onMeasureStart', this.showMeasure, this );
			viewer.on('onMeasureStop', this.hideMeasure, this);
			viewer.on('onMeasureChanging', this.displayMeasure, this);
			viewer.on('onMeasureChanged', this.displayMeasure, this);
		}
	}


});
 /* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloPanelBase
 * @extends Ext.Panel
 * 
 * 
 */
Ext.define('TolomeoExt.ToloPanelBase', {

	extend: 'Ext.Panel',
	
	alias: 'tx_ToloPanelBase',
	
	/** 
	 * @property {Object} paramsJS
	 * 
	 * 
	 */
	paramsJS: null,

	/** 
	 * @property {String} TOLOMEOServer
	 * 
	 * 
	 */
	TOLOMEOServer: null,

	/** 
	 * @property {String} TOLOMEOContext
	 * 
	 * 
	 */
	TOLOMEOContext: null,
	
	/** 
	 * @property {String} TOLOMEOStaticRoot
	 * 
	 * 
	 */
	TOLOMEOStaticRoot: null,

	/** 
	 * @property {Object} toolbarOpt
	 * Parametri di configurazione per la toolbar 
	 * 
	 */
	toolbarOpt: null,

	/** 
	 * @property {TolomeoExt.ToloButtonPanelExt} toolbar
	 * 
	 * 
	 */
	toolbar: null,
	
	/** 
	 * @property {Object} statusbar
	 * 
	 * 
	 */
	statusbar: null,

	/** 
	 * @property {Object} mapPanel
	 * 
	 * 
	 */
	mapPanel: null,

	/** 
	 * @property {Object} ricercaPanel
	 * 
	 * 
	 */
	ricercaPanel: null,

	/** 
	 * Property: queryBuilderPanel
	 * {} 
	 */
	queryBuilderPanel: null,
	
	/**
	* Property: olsPanel
	* {} 
	*/
	olsPanel: null,
	
	/** 
	 * Property: codeLessPanel
	 * {} 
	 */
	codeLessPanel: null,
	
	/** 
	 * Property: viewCodeLessPanel
	 * {} 
	 */
	viewCodeLessPanel: null,
	
	/** 
	 * Property: legendaPanel
	 * {} 
	 */
	legendaPanel: null,

	/**
	 * @property {TolomeoExt.ToloStylePanel} stylePanel
	 * Pannello di gestione degli stili 
	 * 
	 */
	stylePanel: null,
	
	/** 
	 * @property {Object} viewerConfig
	 * configurazione che sarà utilizzata per il viewer
	 * 
	 */
	viewerConfig: null,

	/** 
	 * @property {Object} APIConfig
	 * configurazione che sarà utilizzata per il viewer
	 * 
	 */
	APIConfig: null,

	/** 
	 * @property {Object} api
	 * 
	 * 
	 */
	api: null,

	/** 
	 * @property {Object} ricercaPanelOpt
	 * 
	 * 
	 */
	ricercaPanelOpt: null,
	
	/** 
	 * Property: queryBuilderPanelOpt
	 * {}
	 */
	queryBuilderPanelOpt: null,
	
	/** 
	 * Property: featureGridPanelOpt
	 * {}
	 */
	featureGridPanelOpt: null,

	/** 
	 * Property: formCodelessPanelOpt
	 * {}
	 */
	formCodelessPanelOpt: null,

	/** 
	 * Property: formViewCodelessPanelOpt
	 * {}
	 */
	formViewCodelessPanelOpt: null,

	/** 
	 * @property {Object} legendaPanelOpt
	 * 
	 * 
	 */
	legendaPanelOpt: null,
	
	/** 
	 * Property: olsPanelOpt
	 * {}
	 */
	olsPanelOpt: null,

	/**
	 * @property {Object} stylePanelOpt
	 * Opzioni di configurazione dell'eventuale pannello di gestione degli stili. Se non definito non viene attivata la funzionalità di gestione stili
	 * 
	 */
	stylePanelOpt: null,
	
	
	/** 
	 * @property {Object} mapPanelOpt
	 * 
	 * 
	 */
	mapPanelOpt: null,
	
	/** 
	 * @property {Object} toolsPanelOpt
	 * 
	 * 
	 */
	toolsPanelOpt: null,
	
	/** 
	 * @property {Object} timeMachinePanelOpt
	 * 
	 * 
	 */
	timeMachinePanelOpt: null,
	
	/** 
	 * @property {String} [titoloMappa='Mappa di Prato']
	 * 
	 * 
	 */
	titoloMappa: null,
	
	/** 
	 * @property {String} descrizioneMappa
	 * 
	 * 
	 */
	descrizioneMappa: null,
	
	/** 
	 * @property {Boolean} [stampaReferer=true]
	 * 
	 * 
	 */
	stampaReferer: true,
	
	 * @property {String} [urlLogo=""]
	 * 
	 * 
	 */
	urlLogo: "",
	
	/** 
	 * @property {String} [urlLogoSecondario=""]
	 * 
	 * 
	 */
	urlLogoSecondario: "",
	
	/** 
	 * @property {Boolean} withDefaultToolbar
	 * Impostare a false se non si desidera che il pannello base imposti la propria tbar
	 * 
	 */
	withDefaultToolbar: true,
	
	/** 
	 * @property {Boolean} withDefaultStatusbar
	 * Impostare a false se non si desidera avere la statusBar
	 * 
	 */
	withDefaultStatusbar: true,

	/**
	 * @method initComponent
	 * Create a new TolomeoExt.ToloPanelBase
	 *
	 * Returns:
	 * {<TolomeoExt.ToloPanelBase>} un nuovo TolomeoExt.ToloPanelBase.
	 */
	initComponent: function() {
		
		if (this.titoloMappa==null) {
			this.titoloMappa = ToloI18n.getMsg("ToloPanelBase.titoloMappa");
		}
		
		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		//this.monitorResize=true;
		
		if (this.toolbarOpt) {
			TolomeoExt.applyIfEmpty(this.toolbarOpt, {
				paramsJS: this.paramsJS, 
				items   : []
			});
			this.toolbar = new TolomeoExt.ToloButtonPanelExt(this.toolbarOpt);
			
			if(this.withDefaultToolbar) {
				this.tbar = this.toolbar;
			}
		}
		
		if(!this.statusbar){
			this.statusbar = new Ext.ux.StatusBar({
	            defaultText: '',
	            statusAlign: 'left',
	            items: []
	        });
	        
	        if(this.withDefaultStatusbar){			
				this.bbar = this.statusbar;
			}
		}		
		
		this.callParent(arguments);
		
		if (this.ricercaPanelOpt) {
    		TolomeoExt.applyIfEmpty(this.ricercaPanelOpt, {
    			title     : ToloI18n.getMsg("ToloPanelBase.ricercaPanelOpt.title"),
			    autoScroll: 'true',
			    iconCls   : 'iconQuery',
			    paramsJS  : this.paramsJS, 
			    items     : new Array()
    		});
			this.ricercaPanel = new TolomeoExt.ToloQueryPanelExt( this.ricercaPanelOpt );
		}
		
		if (this.paramsJS.isQueryBuilder() && this.queryBuilderPanelOpt) {
			
			var qbEventManager = Ext.create('TolomeoExt.events.ToloQueryBuilderEvtManager');
			
			var qbFeatureManager = Ext.create('TolomeoExt.ToloFeatureManager', {
				TOLOMEOServer: this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext
			});
			
    		TolomeoExt.applyIfEmpty(this.queryBuilderPanelOpt, {
    			title     : ToloI18n.getMsg("ToloPanelBase.querybuilder.title"),
			    autoScroll: 'true',
			    iconCls   : 'iconQuery',
			    paramsJS  : this.paramsJS, 
				TOLOMEOServer : this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext,
				caseInsensitiveMatch: false,
				qbFeatureManager: qbFeatureManager,
				qbEventManager: qbEventManager,
				
				autoCompleteCfg: {
					url: this.TOLOMEOServer + this.TOLOMEOContext + '/UniqueValueServlet',
					pageSize: 10
				},				
				autoComplete: true,
			    items     : new Array()
				//,ogcFilterVersion : '1.0.0'
    		});
			this.queryBuilderPanel = Ext.create('TolomeoExt.ToloQueryBuilderExt',  this.queryBuilderPanelOpt);
			
    		TolomeoExt.applyIfEmpty(this.featureGridPanelOpt, {
    			title     : ToloI18n.getMsg("ToloPanelBase.grigliaris.title"),
			    autoScroll: 'true',
				border: false,
				layout: 'fit',
			    paramsJS  : this.paramsJS, 
			    qbFeatureManager: qbFeatureManager,
			    qbEventManager: qbEventManager,
			    items     : new Array()
    		});
			this.featureGridPanel = Ext.create('TolomeoExt.ToloFeatureGridPanel',  this.featureGridPanelOpt);
		}
		
		if (this.paramsJS.layOut.ols && this.olsPanelOpt) {
		 		TolomeoExt.applyIfEmpty(this.olsPanelOpt, {
		   			title     : ToloI18n.getMsg("ToloPanelBase.ols.title"),
				    autoScroll: 'true',
				    iconCls   : 'iconQuery',
				    paramsJS  : this.paramsJS
		   		});
				this.olsPanel = new TolomeoExt.OLS.ToloOLSPanelExt( this.olsPanelOpt );
		}
		
		// /////////////////////
		// Codeless Panel
		// /////////////////////
		if(this.paramsJS.withCodeless() && this.formCodelessPanelOpt){
    		TolomeoExt.applyIfEmpty(this.formCodelessPanelOpt, {
    			//title     : 'Codeless Form',
    			header: false,
			    autoScroll: 'true',
			    iconCls   : 'iconCodelss',
			    paramsJS  : this.paramsJS, 
				TOLOMEOServer : this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext,
//				cmdToolbar: this.toolbar,
			    items     : new Array()
    		});
			this.codeLessPanel = Ext.create('TolomeoExt.ToloCodeLessPanel',  this.formCodelessPanelOpt);
		}
		
		if(this.paramsJS.withViewCodeless() && this.formViewCodelessPanelOpt){
    		TolomeoExt.applyIfEmpty(this.formViewCodelessPanelOpt, {
    			//title     : 'New Codeless Form',
    			header: false,
			    autoScroll: 'true',
			    iconCls   : 'iconCodelss',
			    paramsJS  : this.paramsJS, 
				TOLOMEOServer : this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext,
//				cmdToolbar: this.toolbar,
			    items     : new Array()
    		});
			this.viewCodeLessPanel = Ext.create('TolomeoExt.ToloViewCodeLessPanel',  this.formViewCodelessPanelOpt);
		}
		
		if (this.legendaPanelOpt) {
			TolomeoExt.applyIfEmpty(this.legendaPanelOpt, {
				title         : ToloI18n.getMsg("ToloPanelBase.legenda.title"),
				autoScroll    : 'true',
				cls           : 'clearCSS',
				iconCls       : 'iconToc',
				paramsJS      : this.paramsJS,
				TOLOMEOServer : this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext,
				TOLOMEOStaticRoot: this.TOLOMEOStaticRoot,
				xtype         : 'tx_toloTreeTOCPanelExt'
				
			});

			this.legendaPanel =  Ext.widget(this.legendaPanelOpt);
		}

		if (this.stylePanelOpt) {
			TolomeoExt.applyIfEmpty(this.stylePanelOpt, {
				closeAction: 'hide',
				TOLOMEOServer: this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext,
				TOLOMEOStaticRoot: this.TOLOMEOStaticRoot,
				width: 500,
				height: 250
			});
			this.stylePanelOpt.closeAction = 'hide';
			
			this.stylePanel = new TolomeoExt.ToloStylePanel(this.stylePanelOpt); 
		}
		
		
		if (this.timeMachinePanelOpt) {
			
			if (this.timeMachinePanelOpt.carouselConfig) {
				
				TolomeoExt.applyIfEmpty(this.timeMachinePanelOpt.carouselConfig, {
					interval: 3,
				    autoPlay: true,
				    showPlayButton: true,
				    pauseOnNavigate: true,
				    freezeOnHover: true,
				    transitionType: 'fade',
				    transitionEasing: 'fadeIn',    
				    navigationOnHover: false    
					
					});
			} else {
				this.timeMachinePanelOpt.carouselConfig = {
						interval: 3,
					    autoPlay: true,
					    showPlayButton: true,
					    pauseOnNavigate: true,
					    freezeOnHover: true,
					    transitionType: 'fade',
					    transitionEasing: 'fadeIn',    
					    navigationOnHover: false    
						
						};
			}
			
    		TolomeoExt.applyIfEmpty(this.timeMachinePanelOpt, {
    			title     : ToloI18n.getMsg("ToloPanelBase.timemachine.title"),
    			paramsJS      : this.paramsJS
    		});
			this.timeMachinePanel = new TolomeoExt.ToloTimeMachinePanel( this.timeMachinePanelOpt );
		}
		
	    var cfg = Ext.apply({}, this.viewerConfig);		
	    cfg.bOnOpenDrawMap = ((this.APIConfig!=null) && (this.APIConfig.openActionsJS!=null)) ? false : (this.viewerConfig!=null) ? this.viewerConfig.bOnOpenDrawMap : true;
		TolomeoExt.applyIfEmpty (cfg, {
	    	region    : 'center',
	        xtype     : "tx_toloviewerOLPanel",
		    "paramsJS": this.paramsJS
	    });
		
		this.mapPanel = new TolomeoExt.ToloViewerOLPanel(cfg);	 		
		
    },
    
    /**
     * @method afterRender
     * @private
     * Metodo privato invocato dopo che il pannello è stato renderizzato.
     * 
     */
    afterRender: function() {	
    	this.callParent(arguments);
    	if (this.api==null) {
	    	var cfg = Ext.apply({}, this.APIConfig);
	    	this.api = Ext.create('TolomeoExt.ToloMapAPIExt', Ext.apply(cfg,{
				"paramsJS"        : this.paramsJS,
				TOLOMEOServer	  : this.TOLOMEOServer,
				TOLOMEOContext	  : this.TOLOMEOContext,
				TOLOMEOStaticRoot : this.TOLOMEOStaticRoot,
				viewer            : this.mapPanel,
				buttonsPanel      : this.toolbar,
				TOCPanel          : this.legendaPanel,
				stylePanel		  : this.stylePanel,
				queryPanel        : this.ricercaPanel,
				olsPanel          : this.olsPanel,
				queryBuilderPanel : this.queryBuilderPanel,
				featureGridPanel  : this.featureGridPanel,
				codeLessPanel     : this.codeLessPanel,
				viewCodeLessPanel : this.viewCodeLessPanel,
				titoloMappa       : this.titoloMappa,
				descrizioneMappa  : this.descrizioneMappa,
				urlLogo           : this.urlLogo,
				urlLogoSecondario : this.urlLogoSecondario,
				stampaReferer     : this.stampaReferer,
				statusPanel       : this.statusbar
			}));		    	
		}
    }		
});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * @class TolomeoExt.ToloScaleComboExt
 * @extends Ext.form.ComboBox
 * Una combo box che consente di scegliere la scala della mappa
 *
 */ 
Ext.define('TolomeoExt.ToloScaleComboExt', {

	extend: 'Ext.form.ComboBox',
 
	/** 
	 * @property {Number} [width=180]
	 * 
	 * 
	 */
	width:180,
	
	/** 
	 * @property {Number} [labelWidth=60]
	 * 
	 * 
	 */
	labelWidth:60,

	/** 
	 * @property {String} [listClass='scaleListCss']
	 * 
	 * 
	 */
	formItemCls:'scaleListCss' , 
	
	/*
	 * @property {String} [listClass='scaleListCss']
	 * 
	 * 
	 */
	// listClass: 'scaleListCss' , 

	/** 
	 * @property {Boolean} [forceSelection=false]
	 * false, per non forzare la scelta dalla lista
	 * 
	 */
	forceSelection: false, 

	/** 
	 * @property {String} [fieldLabel='Scala ']
	 * 
	 * 
	 */
	fieldLabel: null,

	/** 
	 * @property {String} [labelSeparator='=']
	 * 
	 * 
	 */
	labelSeparator : '=',

	/** 
	 * @property {String} [labelStyle='font-weight:bold;text-align:right;width:60px;']
	 * 
	 * 
	 */
	labelStyle: 'font-weight:bold;text-align:right;width:60px;',

	/** 
	 * @property {String} [listAlign='bl-tl']
	 * 
	 * 
	 */
	listAlign: 'bl-tl',

	/** 
	 * @property {RegExp} [maskRe=/\d/]
	 * 
	 * 
	 */
	maskRe:/\d/,     

	/** 
	 * @property {String} [triggerAction='all']
	 * 
	 * 
	 */
	triggerAction: 'all',

	/** 
	 * @property {String} [emptyText='']
	 * 
	 * 
	 */
	emptyText: '',

	/** 
	 * @property {Boolean} [selectOnFocus=true]
	 * 
	 * 
	 */
	selectOnFocus: true,
	
	/** 
	 * @property {String} [displayTpl='<tpl for=".">1 : {[Ext.util.Format.number(parseInt(values.scaleValue),"0,000")]}</tpl>']
	 * 
	 * 
	 */
	displayTpl:'<tpl for=".">1 : {[Ext.util.Format.number(parseInt(values.scaleValue),"0,000")]}</tpl>',
        
	/** 
	 * @property {Object} listConfig
	 * 
	 * 
	 */
    listConfig: {
        // Custom rendering template for each item
        getInnerTpl: function() {    
            //return '1 : {[Ext.util.Format.number(parseInt(values.scaleValue),"0,000")]}';
        	
        	 return '{[values.custom ? "<span style=\\"color:red;\\">1 : " + Ext.util.Format.number(parseInt(values.scaleValue),"0,000") + "</span>": "1 : " + Ext.util.Format.number(parseInt(values.scaleValue),"0,000")]}';
        }
    },

	/*
	 * @property {Boolean} [editable=false]
	 * 
	 * 
	 */
    //editable : false,
    
	/*
	 * @property {Boolean} [forceSelection=true]
	 * 
	 * 
	 */
    //forceSelection : true,
    
	/*
	 * @property {Boolean} [hideTrigger=false]
	 * 
	 * 
	 */
    //hideTrigger:false,
    	
	/** 
	 * @property {String} [valueField='scaleValue']
	 * 
	 * 
	 */
	valueField: 'scaleValue',

	/** 
	 * @property {String} [displayField='scaleDescr']
	 * 
	 * 
	 */
	displayField: 'scaleDescr',

	/** 
	 * @property {Boolean} [enableKeyEvents=true]
	 * 
	 * 
	 */
	enableKeyEvents: true,
	
	/** 
	 * @property {String} [queryMode='local']
	 * 
	 * 
	 */
	queryMode: 'local',
	
	/** 
	 * @property {Object} listeners
	 * 
	 * 
	 */
	listeners : {
		
	    select: {
	        fn: function(){
	            this.notifyChange(this.getValue());
	            return false;
	        }
	    },	   	   
	    
	    specialkey: {	    	
	       fn: function(cb, e){
	       		var me = this;
	          	if (e.getKey() == e.ENTER) {	              	              
	              // if record is not present in the store we add it temporary to store to make manage the value at the combobox  	          	 
	          		var v = cb.getValue();	 	          		
			        cb.forceValue(v);
	             	cb.notifyChange(v);
	             	return false;
	          	}
	       }
	     },
	    
	     afterRender: {
	        fn: function() {
	            var me = this;                    
	            // Also if editable allows opening the picker by clicking the field
	            if (this.editable) {
	                 me.mon(me.inputEl, 'click', me.onTriggerClick, me);
	            }
	        }
	     },
	     
	     click: {
	     	fn: function(e){
	     		e.stopEvent();
	     	}
	     }
	},

	/**
	 * @method initComponent
	 * Crea un nuovo TolomeoExt.ToloScaleComboExt.
	 * 
	 */		
	initComponent: function() {
		
    	// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
	
		this.fieldLabel = ToloI18n.getMsg("ToloScaleComboExt.fieldLabel");
		
	    this.addEvents('scalechange');	    
		       
/*
	    this.plugins = [ new Ext.DomObserver({
          click: function(evt, comp) {
              comp.onLoad.defer(10,this);  
              comp.setRawValue(comp.getValue());    
              comp.selectByValue(comp.getValue());              
              comp.selectText();
          }
        })];	    
*/
        this.callParent(arguments);	
    
		Ext.util.CSS.createStyleSheet('.scaleListCss{text-align: right;}','scaleListCss');

	},
			
	/**
	 * @method cleanValue
	 * Clean the value of the scale from bad character
	 * 
	 * @param {String} val
	 * val.
	 * 
	 */
	cleanValue : function(val){
	    return (""+val).replace(/^(\s*1\s*:)?|[^0-9]/g,'');
	},
	  
	/**
	 * @method notifyChange
	 * Private method to notify a scale change
	 * 
	 * @param {String} val
	 * value
	 * 
	 */
	notifyChange : function(val){		
	    this.fireEvent('scalechange', this.cleanValue(val));	
	},
	
	/*
	 * @method forceValue
	 * Call this method to set the scale value desired
	 * 
	 * @param {Object} val
	 * 
	 * 
	forceValue : function(val){
        var v = parseInt(this.cleanValue(val)); 
        
        this.resetFilter();
        
        if(this.findRecordByValue(v)){
            this.select(v);
        } else {            
            var scaleStore = this.getStore();
            scaleStore.add({scaleValue : v, scaleDescr : '' + v});
            var r = this.findRecordByValue(v);
            this.setValue(v);
            scaleStore.rejectChanges();
            
        }
    },
    */
	
	/**
	 * @method forceValue
	 * Call this method to set the scale value desired
	 * 
	 * @param {Object} val
	 * 
	 * 
	 */
	forceValue : function(val){
		
            var v = parseInt(this.cleanValue(val)); 
            var scaleStore = this.getStore();
            
            this.resetFilter();
            var f = this.findRecordByValue(v);            
             
            if(f){                
                this.select(v);
                /*
                if(!f.get('custom')){
                    scaleStore.rejectChanges();
                }
                */
            } else {   
                scaleStore.rejectChanges();
                scaleStore.add({scaleValue : v, scaleDescr : '' + v, custom : true});
                var r = this.findRecordByValue(v);
                this.setValue(v);
                //scaleStore.rejectChanges();                
            }
        },
    
    /**
	   * @method resetFilter
	   * Clean the query filter to have the complete list of items
	   * 
  	 */
    resetFilter : function(){
    	var st = this.getStore();	          		
  		var filter = this.queryFilter;
  		
        // If filtered on typed value, unfilter.
        if (filter && !filter.disabled) {
            filter.disabled = true;
            st.filter();
        }	    
    }
});
 
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


 
/**
 * @class TolomeoExt.ToloScalePanelExt
 * @extends Ext.FormPanel
 * 
 * 
 */ 
Ext.define('TolomeoExt.ToloScalePanelExt', {

	extend: 'Ext.FormPanel',
 
 	/** 
	   * @property {Boolean} [autoHeight=true]
	   * 
	   * 
		 */
        autoHeight: true,
        
    	/** 
         * @property {String} [bodyCssClass='scaleFormCss']
         * 
         * 
      	 */
        bodyCls : 'scaleFormCss',  
        
    	/** 
         * @property {Number} [width=190]
         * 
         * 
      	 */
        width: 190,
        
    	/** 
         * @property {Boolean} [bodyBorder=true]
         * 
         * 
      	 */
        bodyBorder: true,
        
    	/** 
         * @property {Array} [defaultZoomLevels=[]]
         * 
         * 
      	 */
        defaultZoomLevels: [],
        
    	/** 
         * @property {Object} scaleCombo
         * 
         * 
      	 */
        selectorConfig : null,    
        
        /** 
         * @property {Boolean} [settableZoom=true]
         * 
      	 */
        settableZoom : true,
        
    	/**
         * @method initComponent
         * Crea un nuovo TolomeoExt.ToloScalePanelExt.
         * 
         */			
        initComponent: function() {
          
          this.addEvents('scalechange');
          
          this.callParent(arguments);
		 // Ext.util.CSS.createStyleSheet('.scaleFormCss{padding: 5px 0px 2px 0px; background-color: transparent;   }','scaleFormCss');
		  this.defaultZoomLevels.sort(function(a,b){return b - a});
		      
          var myData = new Array();		      
		      
		  for(var i = 0; i < this.defaultZoomLevels.length; i++){            
          	myData.push([this.defaultZoomLevels[i],'1 : ' + Ext.util.Format.number(this.defaultZoomLevels[i],'0,000',false)]);            
          }
		  
          var myStore = new Ext.data.ArrayStore({
              fields: [
                {name: 'scaleValue', type: 'number'},
	            {name: 'scaleDescr', type: 'string'},
	            {name: 'custom', type: 'boolean'}                 
              ],
              data : myData,
              sorters: [{
		         sorterFn: function(o1, o2){
		                
			         var v1 = o1.get('scaleValue');
			         var v2 = o2.get('scaleValue');
			    
			         if (v1 == v2) {
			         	return 0;
			         }		    
			         
			         return v1 < v2 ? 1 : -1;
		         }
		      }]
          });
          
          var selectorConfig = Ext.applyIf({
          	store:myStore,
          	editable: this.settableZoom          
          }, this.selectorConfig);
          
                    
          this.zoomSelector = new TolomeoExt.ToloScaleComboExt(selectorConfig);    
          this.zoomSelector.on('scalechange', function(val) {this.fireEvent('scalechange', val)} , this );      
          this.add(this.zoomSelector);                   
        
        },
        
        /**
         * @method bindToViewerPanel
         * 
         * 
         * @param {Object} viewer
         * viewer
         * 
         */
        bindToViewerPanel: function(viewer) { 
      		if (viewer!=null) {
      			// mi registro sulla variazione di scala del viewer
      			viewer.on('scalechange', this.setScale, this );      			
      			viewer.on('onAfterPostInit', 
      				function(){ this.on('afterlayout', function(){ 
									this.setScale(viewer.pluginGetCurrentZoom()); 
								}, 
					this, {single: true});}, this );       			
      			// se la combo non perde il focus firefox dopo il cambio di dimensione non sente il click
      			viewer.on('resize', function(){if(this.zoomSelector.getEl())this.zoomSelector.getEl().dom.blur()}, this );		      			
      		}
      	},
      	
      	/**
      	 * @method setScale
      	 * 
      	 * 
      	 * @param {Number} val
      	 * val
      	 * 
      	 */
      	setScale : function(val){      	      		
        	this.zoomSelector.forceValue(Math.round(val));          
        }                               
});    
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITA' o
 IDONEITA' PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 *   
 * @class Pannello ExtJs contenente una mappa visualizzata utilizzando openlayers. 
 * @param config {Object} Oggetto contenente i parametri di configurazione. Sono ammessi tutti i parametri previsti per ExtJS.Panel ed i seguenti parametri aggiuntivi
 * @param config.paramsJS {Object} Oggetto i parametri contenuti nel file di preset.
 * @param config.customQuery {String} [] Filtro di visualizzazione 
 * 
 */

/**
 * Class: TolomeoExt.ToloViewerOLPanel
 *
 * Inherits from:
 *  - <Ext.Panel>
 *
 */
Ext.define('TolomeoExt.ToloViewerOLPanel', {

	extend: 'Ext.Panel',	
	alias: 'tx_toloviewerOLPanel',
	
	statics: {
		getWKTParts: function(wktIn) {
			if (wktIn.indexOf('MULTI')==-1){
				return [ wktIn ];
			}
			var retVal = [];
			var wktParser = new OpenLayers.Format.WKT();
			var g = OpenLayers.Geometry.fromWKT(wktIn);
			
			var parts = g.components;
			if (parts) {
				if (parts.length==1){
					return [ wktIn ];
				} else {
					for (var i=0; i<parts.length; i++) {
						var p = parts[i];
						p.getBounds().toBBOX();
						retVal.push(wktParser.extractGeometry(p));	
					}
				}
			}
			
			return retVal;
		},
		
		customQueryForServer: function(customQuery, serverID){
			var retVal = {};
			
			for (var p in customQuery) {
				if (customQuery[p] instanceof Object) {
					if (p == serverID) {
						Ext.apply(retVal, customQuery[p]);
					}
				} else {
					retVal[p] = customQuery[p];
				}
			}
			return retVal;
		},
		
		customQueryToGeoserverObj: function(cqForServer){
			
			var wmsParams = {};
			for (var i in cqForServer) {
				if (wmsParams.viewparams==undefined) wmsParams.viewparams = '';
				wmsParams.viewparams += ((wmsParams.viewparams!='') ? ';' : '') + i + ':' + cqForServer[i];
			}
			return wmsParams;
			
		}, 
		
		customQueryToMapserverObj: function(cqForServer){
			return cqForServer;
		}
		
	},
	
	/** 
	 * Property: TOLOMEOServer
	 * {String}
	 */
	TOLOMEOServer: null,

	/** 
	 * Property: TOLOMEOContext
	 * {String}
	 */
	TOLOMEOContext: null,
	
	/** 
	 * Property: TOLOMEOStaticRoot
	 * {String}
	 */	
	TOLOMEOStaticRoot: null, 

	/** 
	 * @property {Boolean} withWmsCallUUID 
	 * controlla se deve essere aggiunta uuid ad ogni chiamata
	 * 
	 */	
	withWmsCallUUID: null, 
	
	/**
	 * UUID da aggiungere alle chiamate WMS
	 */
	wmscalluuid: null,
	
	
	/** 
	 * Property: digitizeOperationInsert
	 * {OpenLayers.Map} Mappa openlayers viasualizzata in questo pannello
	 */
	map: null,

	/** 
	 * Property: mapControls
	 * {Openlayer.Controls} Vettore contenente i controlli openlayers attivi su map
	 */
	mapControls: null,
	
	/** 
	
	/** 
	 * Property: drawLayer
	 * {} 
	 */
	drawLayer: null,

	/** 
	 * Property: selezioniLayer
	 * {} 
	 */
	selezioniLayer: null,

	/** 
	 * Property: evidenziazioniLayer
	 * {}
	 */
	evidenziazioniLayer: null,
	
	 /**
	 * Property: routingLayer
	 * {}
	 */
	 routingLayer: null,
	 
	 /** 
	 * Property: routingMarkersLayer
	 * {}
	 */
	 routingMarkersLayer: null,
	 	
	 /** 
	  * Property: startMarker
	  * {}
	  */
	 startMarker: null,
	 
	 /** 
	 * Property: endMarker
	 * {}
	 */
	 endMarker: null,
	 
	 /** 
	  * Property: viaMarkers
	  * {}
	  */
	 viaMarkers: [],

	 /** 
	/** 
	 * Property: paramsJS
	 * {JSONObject} Oggetto i parametri contenuti nel file di preset.
	 */
	paramsJS: null, 

	/** 
	 * Property: customQuery
	 * {Object} Oggetto
	 */
	customQuery: null,

	/** 
	 * Property: mapBusy
	 * {Integer}
	 */
	mapBusy: 0,

	/** 
	 * Property: myMask
	 * {}
	 */
	myMask: null,

	/** 
	 * Property: isAlreadyDrawn
	 * {} Variabile che indica se e' gia stata disegnata (utilizzato in preinit e postinit
	 */
	isAlreadyDrawn: null, 

	/** 
	 * Property: olViewerToolSelectSelectEventHandler
	 * {}
	 */
	olViewerToolSelectSelectEventHandler:  null, 

	/** 
	 * Property: mapPanel
	 * {} 
	 */
	mapPanel: null,

	/** 
	 * Property: measurePanel
	 * {}
	 */
	measurePanel: null, 

	/** 
	 * Property: timeMachinePanel
	 * {}
	 */
	timeMachinePanel: null, 
	
	/** 
	 * Property: scalePanel
	 * {}
	 */
	scalePanel: null, 
	
	/** 
	 * Property: withScaleLine
	 * {}
	 */
	withScaleLine: true,
	
	/** 
	 * Property: withScaleSelector
	 * {}
	 */
	withScaleSelector: true,

	/** 
	 * Property: monitoito
	 * {Boolean}
	 */
	//monitorResize: true,

	/** 
	 * Property: bOnOpenDrawMap
	 * {Boolean} Indica se disegnare la mappa in apertura 
	 */
	bOnOpenDrawMap: null,
	
	styleSelected: null,
	
	styleHighlighted: null,
	
	styleAutoidentify: null,
	
	styleSnap: null,
	
	styleMeasure: null,
	measurePointSymbolizer: null,
	measureLineSymbolizer: null,
	measurePolygonSymbolizer: null,
	
	layerTypePrereq: [	[""],  // 0 - Mapserver
					   	["http://maps.google.com/maps?file=api&amp;key=ABQIAAAAjpkAC9ePGem0lIq5XcMiuhR_wWLPFku8Ix9i2SXYRVK3e45q1BQUd_beF8dtzKET_EteAjPdGDwqpQ",
					   	 "http://maps.google.com/maps/api/js?v=3.2&sensor=false"],  // case 1:	// Google Streets	
						["http://maps.google.com/maps?file=api&amp;key=ABQIAAAAjpkAC9ePGem0lIq5XcMiuhR_wWLPFku8Ix9i2SXYRVK3e45q1BQUd_beF8dtzKET_EteAjPdGDwqpQ",
						 "http://maps.google.com/maps/api/js?v=3.2&sensor=false"],  // case 2:	// Google Physical
						["http://maps.google.com/maps?file=api&amp;key=ABQIAAAAjpkAC9ePGem0lIq5XcMiuhR_wWLPFku8Ix9i2SXYRVK3e45q1BQUd_beF8dtzKET_EteAjPdGDwqpQ",
						 "http://maps.google.com/maps/api/js?v=3.2&sensor=false"],  // case 3:	// Google Satellite
						["http://maps.google.com/maps?file=api&amp;key=ABQIAAAAjpkAC9ePGem0lIq5XcMiuhR_wWLPFku8Ix9i2SXYRVK3e45q1BQUd_beF8dtzKET_EteAjPdGDwqpQ",
						 "http://maps.google.com/maps/api/js?v=3.2&sensor=false"],  // case 4:	// Google Hybrid
						["http://api.maps.yahoo.com/ajaxymap?v=3.0&appid=euzuro-openlayers"],  // case 5:	// Yahoo Sat 
						["http://api.maps.yahoo.com/ajaxymap?v=3.0&appid=euzuro-openlayers"],  // case 6:	// Yahoo Reg
						["http://api.maps.yahoo.com/ajaxymap?v=3.0&appid=euzuro-openlayers"],  // case 7:	// Yahoo Hybrid
						["http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&mkt=en-us"],  // case 8:	// Bing Aerial
						["http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&mkt=en-us"],  // case 9:	// Bing Shaded
						["http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&mkt=en-us"],  // case 10:	// Bing Hybrid
						[""],  // case 11:	// WMS 	    		
						[""]  // case 12:	// OpenStreetMap
					], 
	  
	streetViewMarkerLayer: null,
	streetViewDragControl: null,
	streetViewNavigationLinkLayer: null,
	streetviewSelectControl: null,
	streetviewHighlightCtrl: null,
					
	// Array contentente i layer di mappa (non quelli di servizio come i layer di evidenziazione, selezione etc.)
	layersMappa: null,
	
	/**
	 * Method: initComponent
	 * Metodo ExtJS initComponent 
	 */
	initComponent: function(){
		TolomeoExt.applyIfEmpty(this, {bOnOpenDrawMap: true});
		//Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);	
		// se non definiti definisco altezza e larghezza (altrimenti problemi con IE)
		TolomeoExt.applyIfEmpty(this, { width: 50, height: 50});
		
		if  (this.withWmsCallUUID==null) {
			if (this.paramsJS.comportamento && this.paramsJS.comportamento.withWmsCallUUID) {
				this.withWmsCallUUID = true;
			} else {
				this.withWmsCallUUID = false;
			}
		}
		
		if (this.withWmsCallUUID) {
			this.wmscalluuid = uuid.v4();
		}
		
		this.layersMappa = [];
		this.layout = 'absolute';
		//this.pluginPreInit();
				
		// add custom events
        this.addEvents('scalechange');
    
        this.addEvents('loadstart');
        this.addEvents('loadend');
        this.addEvents('loadcancel');
        
        this.addEvents('onAutoIdentify');
        this.addEvents('onAutoIdentifyCancel');

        this.addEvents('onDigitizeEndPoint');
        this.addEvents('onDigitizeEndLine');
        this.addEvents('onDigitizeEndPolygon');
        this.addEvents('onDigitizeEndVertexEditing');
        this.addEvents('onDigitizeEndDragDrop');
        this.addEvents('onMappaSelect');
        this.addEvents('onMeasureStart');
        this.addEvents('onMeasureStop');
        this.addEvents('onMeasureChanging');
        this.addEvents('onMeasureChanged');
        this.addEvents('onMeasureClear');
        
        this.addEvents('onBeforePreInit');
        this.addEvents('onBeforePostInit');
        this.addEvents('onAfterPreInit');
        this.addEvents('onAfterPostInit');
         				
        this.addEvents('onDigitizedFeatureDragDropEnd');
        this.addEvents('onDigitizedFeatureVertexEditingEnd');
        				
        this.addEvents('onMapMoveEnd');
        
        // L'evento trasmette l'url dell'immagine come primo parametro
        this.addEvents('onPrintMap');
        
        this.addEvents('onDrawDistanceFromRefChange');
        this.addEvents('onDrawFirstPointFromRef');
        this.addEvents('onDigitizePointFromRefEnd');
        this.addEvents('onDrawFirstPointByCAD');
        this.addEvents('onDrawDistanceByCADChange');
        this.addEvents('onDrawAreaByCADChange');
        this.addEvents('onDigitizePointByCADEnd');
        this.addEvents('onDigitizeLineByCADEnd');
        this.addEvents('onDigitizePolygonByCADEnd');
        
        //this.addEvents('onCoordinateChange');
        
        this.addEvents('onStreetviewDropComplete');
        this.addEvents('onStreetviewNavLinkClick');
        
        this.addEvents('onTimeMachineShow');
        this.addEvents('onTimeMachineHide');
        
        this.addEvents('onMouseCoordChange');
        this.addEvents('popupClicked');
        
        // Eventi realtivi a routing
        this.addEvents('startPointMoved');
        this.addEvents('endPointMoved');
        this.addEvents('viaPointMoved');
        this.addEvents('routingInformationSelect');
        this.addEvents('routingInformationUnSelect');
                
        this.addEvents('previousNavigationStateAvailable');
        this.addEvents('previousNavigationStateNotAvailable');
        this.addEvents('nextNavigationStateAvailable');
        this.addEvents('nextNavigationStateNotAvailable');        
        
        this.callParent(arguments);
        
        var thisPanel = this;
        
        
        /* Eventuale possibilita di pannello dei widget da valutare
        this.widgetPanel = Ext.create('Ext.panel.Panel',{
        	layout : 'auto',
			anchor : '100% 100%',
			html : 'eccomi',			 
			dockedItems: [{
		        xtype: 'toolbar',
		        dock: 'top',
		        style: 'background-image: none !important; background: transparent !important;',
		        items: [{
		            text: 'Docked to the top'
		            
		            //style: 'position: absolute; z-index: 100;'
		        }]
		    }]
		});
		*/
		
		this.add(this.widgetPanel);
        
        this.mapPanel = new Ext.Panel({	
        	style: 'z-index:0;',
			layout: 'fit',	
			bodyBorder: false,
			border: false,
			anchor: '100% 100%',			
		//	monitorResize: true,
			listeners: { 
        				resize: {
								fn: function() {
									this.updateMapSize();
								}
							},
						afterrender: { 
							fn: function(){
									if(!this.ownerCt) {
							            this.renderMap();
							        } else {
							            this.ownerCt.on("move", this.updateMapSize, this);
							            this.ownerCt.on({
							                "afterlayout": this.afterLayout,
							                scope: this
							            });
							        }
								} 
						} 
				
					},
			afterLayout: function() {
								var width = this.body.getWidth() - this.body.getBorderWidth("lr");
								var height = this.body.getWidth() - this.body.getBorderWidth("tb");
								if (width > 0 && height > 0) {
									// Non funziona quindi aggiunto if this.ownerCt.un("afterlayout", this.afterLayout, this);
									if (!this.bMapRendered) this.renderMap();
									this.bMapRendered=true;
								}
						
						},
		    renderMap: function() {
		    	thisPanel.pluginPreInit();
		    	var map = thisPanel.map;
		        map.render(this.body.dom);
		       // thisPanel.updateLayout();
		        thisPanel.pluginPostInit();
		    },
		    updateMapSize: function() {
		    	if ((thisPanel.map) ) {
		    		thisPanel.map.updateSize();
		    	} 
		    }
			
		});

		this.add(this.mapPanel);										
        
		if (!this.measurePanel) { 
	        this.measurePanel = new TolomeoExt.ToloMeasurePanelExt({style: 'z-index:1;', x: 10, y: 40});
	        this.measurePanel.bindToViewerPanel(this);
	        this.add(this.measurePanel);
	    }		

        if (!this.scalePanel) {
        	
        	var defaultZoomLevels = this.getDefaultZoomLevels(); 
        	
        	var scalePanelConfig = {
        		defaultZoomLevels: defaultZoomLevels,
	        	settableZoom : this.paramsJS.mappe.settableZoom
        	}
        	
        	// If without scale line just few params are necessary otherwise we need other params
	        if(!this.withScaleLine && this.withScaleSelector) {
        		scalePanelConfig = Ext.applyIf({
		          	style: 'z-index: 2; top:auto; left:auto; right: 0px; bottom: 0px'         
		        }, scalePanelConfig);
	        } else if (this.withScaleLine && !this.withScaleSelector) { 
	        
	        	this.scaleLineBox = Ext.create('Ext.Component',{										
				    autoEl:{
				        tag:"div",			       
				        style: 'font-family: tahoma,arial,helvetica,sans-serif; font-size: xx-small;'
				    },					    
				    flex: 1			    
				});
				
				var scaleWidget = Ext.create('Ext.Panel', {		        		        
		         	width: 50,
	                height: 32,
	                bodyCls : 'scaleFormCss',
	                bodyStyle : 'padding: 4px;',
	                layout: {
	                    type: 'hbox',
	                    pack: 'end'
	                },
	                
	                defaults: {
	                    border: false
	                },
	                style: 'position: absolute; right: 0px; bottom: 0px; z-index: 2;',                
	                items: [this.scaleLineBox]
			     });
			     
			     this.add(scaleWidget);
	        
	        } else if (this.withScaleLine && this.withScaleSelector) {
        		scalePanelConfig = Ext.applyIf({
		          	width: 130,
		        	bodyCls: '',
		        	border: 0,
		        	bodyBorder: false,
		        	selectorConfig : {
		        		labelWidth:0,
						fieldLabel:'',
						labelSeparator : '',
						width: 130
		        	}        
		        }, scalePanelConfig);        		
        	}
        	
        	this.scalePanel = new TolomeoExt.ToloScalePanelExt(scalePanelConfig);	 
	        this.scalePanel.on('scalechange',function(val){this.pluginZoomToScale(val);},this);    	 
	        
	        this.scalePanel.bindToViewerPanel(this);
	        
	        // If without scale line add just the scale panel otherwise create the right widget with Component the will contain the scaleline control of Openlayers
	        if(!this.withScaleLine) {
	        	
	        	this.add(this.scalePanel);
	        	
	        } else {
	        
		        this.scaleLineBox = Ext.create('Ext.Component',{										
				    autoEl:{
				        tag:"div",			       
				        style: 'font-family: tahoma,arial,helvetica,sans-serif; font-size: xx-small;'
				    },					    
				    flex: 1			    
				});
				
				var scaleWidget = Ext.create('Ext.Panel', {		        		        
		         	width:230,
	                height: 32,
	                bodyCls : 'scaleFormCss',
	                bodyStyle : 'padding: 4px;',
	                layout: {
	                    type: 'hbox',
	                    pack: 'end'
	                },
	                
	                defaults: {
	                    border: false
	                },
	                style: 'position: absolute; right: 0px; bottom: 0px; z-index: 2;',                
	                items: [this.scaleLineBox,this.scalePanel]
			     });
			     
			     this.add(scaleWidget);
	        }			
        }
        
        this.pointFromRefPanel = new TolomeoExt.ToloPointFromRefPanelExt({style: 'z-index:1;', x: 10, y: 40});
        this.pointFromRefPanel.on('pressSetDistance', function(distance){this.mapControlsDrawLayer['pointFromRef'].handler.setDistance(distance);}, this);
        this.pointFromRefPanel.bindToViewerPanel(this);
		this.add(this.pointFromRefPanel);
	
        this.cadPanel = new TolomeoExt.ToloCADPanelExt({style: 'z-index:1;', x: 10, y: 40});
        this.cadPanel.bindToViewerPanel(this);
        this.add(this.cadPanel);
        
        /*
		 * Method: runCommandOnPointByCAD
		 * Metodo privato che esegue un comando CAD sul layer di disegno del punto
		 *
		 * Parameters:
		 * command - {String} comando CAD
		 */
        this.runCommandOnPointByCAD = function(command){
			this.mapControlsDrawLayer['pointByCAD'].handler.runCommand(command);
		};
		
		/*
		 * Method: setRelativeAngleOnPointByCAD
		 * Metodo privato che imposta se il valore di un angolo è relativo al lato precedente 
		 * o all'orizzontale per mezzo dell'handler di disegno CAD con punti
		 *
		 * Parameters:
		 * value - {Number} 1 = true (relativo), 0 = false (assoluto)
		 */
		this.setRelativeAngleOnPointByCAD = function(value){
			this.mapControlsDrawLayer['pointByCAD'].handler.setRelativeAngle(Number(value))
		};
		
		/*
		 * Method: delFirstLineOnPointByCAD
		 * Metodo privato che esegue la cancellazione del primo punto per mezzo dell'handler di disegno CAD con punti
		 */
		this.delFirstLineOnPointByCAD = function(){
			this.mapControlsDrawLayer['pointByCAD'].handler.clearFirstPoint();
		};
        
        /*
		 * Method: runCommandOnLineByCAD
		 * Metodo privato che esegue un comando CAD sul layer di disegno della linea
		 *
		 * Parameters:
		 * command - {String} comando CAD
		 */
        this.runCommandOnLineByCAD = function(command){
			this.mapControlsDrawLayer['lineByCAD'].handler.runCommand(command);
		};
		
		/*
		 * Method: setRelativeAngleOnLineByCAD
		 * Metodo privato che imposta se il valore di un angolo è relativo al lato precedente 
		 * o all'orizzontale per mezzo dell'handler di disegno CAD con linee
		 *
		 * Parameters:
		 * value - {Number} 1 = true (relativo), 0 = false (assoluto)
		 */
		this.setRelativeAngleOnLineByCAD = function(value){
			this.mapControlsDrawLayer['lineByCAD'].handler.setRelativeAngle(Number(value))
		};
		
		/*
		 * Method: delFirstLineOnLineByCAD
		 * Metodo privato che esegue la cancellazione del primo punto per mezzo dell'handler di disegno CAD con linee
		 */
		this.delFirstLineOnLineByCAD = function(){
			this.mapControlsDrawLayer['lineByCAD'].handler.clearFirstPoint();
		};
        
		/*
		 * Method: runCommandOnLineByCAD
		 * Metodo privato che esegue un comando CAD sul layer di disegno del poligono
		 *
		 * Parameters:
		 * command - {String} comando CAD
		 */
		this.runCommandOnPolygonByCAD = function(command){
			this.mapControlsDrawLayer['polygonByCAD'].handler.runCommand(command);
		};
		
		/*
		 * Method: setRelativeAngleOnLineByCAD
		 * Metodo privato che imposta se il valore di un angolo è relativo al lato precedente 
		 * o all'orizzontale per mezzo dell'handler di disegno CAD con poligoni
		 *
		 * Parameters:
		 * value - {Number} 1 = true (relativo), 0 = false (assoluto)
		 */
		this.setRelativeAngleOnPolygonByCAD = function(value){
			this.mapControlsDrawLayer['polygonByCAD'].handler.setRelativeAngle(Number(value))
		};
		
		/*
		 * Method: delFirstLineOnLineByCAD
		 * Metodo privato che esegue la cancellazione del primo punto per mezzo dell'handler di disegno CAD con poligoni
		 */
		this.delFirstLineOnPolygonByCAD = function(){
			this.mapControlsDrawLayer['polygonByCAD'].handler.clearFirstPoint();
		};
		
    },
    
    /**
     * Method: updateMapSize
     * Comunica alla mappa che e' necessario ricalcolare dimensioni e posizione.
     * 
     */
    updateMapSize: function() {
    	if ((this.map) && (this.isAlreadyDrawn==true)) {
    		this.map.updateSize();
    	} else {
    		var thisObj = this;
    		//setTimeout(function() { thisObj.updateMapSize();}, 500);
    	}
    },

    
    /**
     * Method: afterRender
     * Metodo privato invocato dopo che il pannello è stato renderizzato.
     * 
     */
    afterRender: function() {    	
    	this.callParent(arguments);
		
    	this.myMask=new Ext.LoadMask(this.id, {msg:ToloI18n.getMsg("ToloViewerOLPanel.afterRender.attesa")});
    	this.refreshBusy();
    	
    },    

    /**
     * Method: onDestroy
     * Metodo privato invocato durantela sequenza di distruzione. 
     */
    onDestroy: function() {
        if(this.ownerCt) {
            this.ownerCt.un("move", this.updateMapSize, this);
        }
        this.callParent(arguments);
    },
    
	
	// Funzioni che devono essere implementate in un plugin dedicato ad un certo viewer
	// Tutte le funzioni sono prefissate con "plugin"
	
    /**
     * Method: pluginPostInit
     * Funzione chiamata da Tolomeo dopo inizializzazione 
     * (come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer).
     * 
     */
	pluginPostInit: function() {
		
		this.fireEvent("onBeforePostInit");
		// se non è già stato disegnato (per esempio da uno zoomTo) allora disegna tutto
		if ((!this.isAlreadyDrawn) && (this.bOnOpenDrawMap==true)) {
			this.map.zoomToMaxExtent();
			this.isAlreadyDrawn=true;
		}
		
		this.fireEvent("onAfterPostInit");
	},
	
	/**
	 * Method: pluginPreInit
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginPreInit: function() {
		var me = this;
		
		this.fireEvent("onBeforePreInit");
	
		// Valorizzazione giusta directory per icone openlayer
		
		OpenLayers.ImgPath = this.TOLOMEOServer + this.TOLOMEOStaticRoot + "js/ext/openlayers/img/";
		
		var layerOptions = new Object();
		
		layerOptions.projection = this.paramsJS.mappe.SRID;
		layerOptions.units = this.paramsJS.mappe.units;
		
		//layerOptions.maxExtent = new OpenLayers.Bounds(1657419, 4852076, 1676400, 4869227);
		
		layerOptions.maxExtent = new OpenLayers.Bounds(this.paramsJS.mappe.maxExtentLeft, this.paramsJS.mappe.maxExtentBottom, this.paramsJS.mappe.maxExtentRight, this.paramsJS.mappe.maxExtentTop);
		layerOptions.minScale = this.paramsJS.mappe.minScale;   //"105000";
		layerOptions.maxScale = this.paramsJS.mappe.maxScale; //="200";

		// Il parametro fallThrough: true è necessario perchè gli eventi di mousemove vengano passati al resto degli oggetti del DOM
		// Se non viene impostato le finestre ExtJS sovrapposte alla mappa si ridimensionano con difficoltà
		var mapOptions = OpenLayers.Util.extend({fallThrough: true}, layerOptions);
		
		mapOptions.controls = [
			//new OpenLayers.Control.Navigation(),
	        //new OpenLayers.Control.PanZoom(), //PanZoom OpenLayers
	        new OpenLayers.Control.ArgParser()
	    //    new OpenLayers.Control.AttributionMulti() // Controllo esteso parte della distribuzione tolomeo
	        //new OpenLayers.Control.OverviewMap(), //Mappa di riferimento
	        //new OpenLayers.Control.ScaleLine()
	        //new OpenLayers.Control.Scale()                            
		];
		
		if(this.withScaleLine){
			var scaleLineOptions = {};
			if(this.scaleLineBox){
				scaleLineOptions.div = this.scaleLineBox.getEl().dom;
			}
			mapOptions.controls.push(new OpenLayers.Control.ScaleLine(scaleLineOptions));
		}
		
	    //commentato perchè se presente con ie6 errore in apertura
	    //, new OpenLayers.Control.MousePosition()
	    
		//mapOptions.controls[2].mapOptions = layerOptions;
		if(this.paramsJS.mappe.settableZoom!=null){
			mapOptions.fractionalZoom = this.paramsJS.mappe.settableZoom;
		}
		
		//OpenLayers.ProxyHost = this.TOLOMEOServer + this.TOLOMEOContext + "/TolomeoProxyServlet?url=";		
		OpenLayers.ProxyHost = this.paramsJS.comportamento.defaultProxyUrl  + "?url=";
		
		mapOptions.allOverlays = true;
		
		// Aggiunto perchè il tile manager dalla 2.13 deve essere specificato anche nel caso si voglia il default, cioè null.		
		mapOptions.tileManager = null;
		
		var zs = this.getDefaultZoomLevels();
		if (zs!=null) {
			mapOptions.resolutions = [];
			for(var i = 0; i < zs.length; i++) {
				mapOptions.resolutions.push(OpenLayers.Util.getResolutionFromScale(zs[i], layerOptions.units));
			}
		} 

		//ALE this.mapPanel.body.id,
		this.map = new OpenLayers.Map( mapOptions);
	
		//TODO Funziona solo con mappa 0
		var nmappa = 0;
		if (this.paramsJS.mappe.mappaList[nmappa].overview) {
		
			var server = this.paramsJS.getServer(this.paramsJS.mappe.mappaList[nmappa].overview.serverID, nmappa);
			
			var ovlayers = new OpenLayers.Layer.WMS( "overview",
	                server.url, 
	                {layers: this.paramsJS.mappe.mappaList[nmappa].overview.layer,
	                 wmscalluuid: (this.withWmsCallUUID) ? this.wmscalluuid : undefined});
		
			// maximized non è stato parametrizzato perchè se aperto all'avvio la mappa di overview viene bianca fino al primo spostamento
			// anche se metto in postinit dopo zoomToMaxExtent
	        var overview1 = new OpenLayers.Control.OverviewMap({
	            //maximized: this.paramsJS.mappe.mappaList[nmappa].overview.maximized,
	        	maximized: false,
	            maximizeTitle: ToloI18n.getMsg("ToloViewerOLPanel.pluginPreInit.overview.max"),
	            minimizeTitle: ToloI18n.getMsg("ToloViewerOLPanel.pluginPreInit.overview.min"),
	            layers: [ovlayers]
	        });
	        this.map.addControl(overview1);
		}
	
		this.map.events.register('mousemove', this, function(e, xy) {
																var lonlat = this.map.getLonLatFromViewPortPx(e.xy);
																this.fireEvent('onMouseCoordChange', new Point(lonlat.lon, lonlat.lat), this.map.units, this.map.getProjection());
																
																});
		
		// registro sull'evento movestart dell'oggetto mappa perchè se lo registrassi sul layer non riceverei l'evento quando il layer è spento
		// (come accade per esempio se non ci sono layer WMS accesi)
		this.map.events.register('movestart', this,  function(obj, element)   { this.olLayerScaleFilter(obj , element);});
		this.map.events.register('preaddlayer', this,  function(obj, element) { this.olLayerScaleFilter(obj , element);});
		
		var elencoLayer = new Array();
		
		this.pluginAddAllMaps();
		
		// Cerca nelle mappe in this.paramsJS.azioniEventi.eventiLayerList
		for (var i = 0; i<this.paramsJS.azioniEventi.eventiLayerList.length; i++) {
			var evLayer = this.paramsJS.azioniEventi.eventiLayerList[i];
			
			if (evLayer.caricaLayerSeparato) {
				var layer = this.olViewerNewLayer (evLayer.mappaLayerSeparato, i+100);
				elencoLayer.push(layer);	
				this.olRegisterBusyEvents(layer);
			}
		}

		this.drawLayer = new OpenLayers.Layer.Vector("DrawLayer");

		
		var styleSelected = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
	    styleSelected.strokeColor = "blue"; 
	    styleSelected.fillColor   = "blue";
	    styleSelected.strokeWidth = 2;
	    styleSelected.fillOpacity = 0.4;
	    styleSelected = OpenLayers.Util.extend(styleSelected,this.styleSelected || {});
	  
		var styleHighlighted = {
			strokeColor  : "#FFCC00",
	        strokeOpacity: 1,
	        strokeWidth  : 2,
	        pointRadius  : 6,
	        pointerEvents: "visiblePainted",
	        fillColor    : "yellow",
	        fillOpacity  : 0.4
		};
		styleHighlighted = OpenLayers.Util.extend(styleHighlighted,this.styleHighlighted || {});
	            
	    var styleAutoidentify = {
			strokeColor  : "#00AA00",
	        strokeOpacity: 1,
	        strokeWidth  : 2,
	        pointRadius  : 6,
	        pointerEvents: "visiblePainted",
	        fillColor    : "#00FF00",
	        fillOpacity  : 0.4
		};
		styleAutoidentify = OpenLayers.Util.extend(styleAutoidentify,this.styleAutoidentify || {});
		
		var styleSnap = {
			strokeColor  : "#00AA00",
			strokeOpacity: 1,
			strokeWidth  : 2,
			pointRadius  : 6,
			pointerEvents: "visiblePainted",
			//fillColor : "#00FF00",
			fillOpacity  : 0
		};
		styleSnap = OpenLayers.Util.extend(styleSnap,this.styleSnap || {});
		
		 var styleRouting = {
				 	strokeColor  : "#00FF00",
				    strokeOpacity: 1,
				    strokeWidth  : 2,
				    pointRadius  : 6,
				    pointerEvents: "visiblePainted",
				    fillColor    : "#00FF00",
				    fillOpacity  : 0.4
		};
		styleRouting = OpenLayers.Util.extend(styleRouting, this.styleRouting || {});
		
	    var styleMeasure = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
	    styleMeasure.strokeColor = "red"; 
	    styleMeasure.fillColor = "green"; 
	    styleMeasure = OpenLayers.Util.extend(styleMeasure,this.styleMeasure || {});
		
		layerOptions.style = styleSelected;
		//coorrezione bug OL2.10
		var a = layerOptions;
		// 14/03/2018 riscontrato problema se a,maxscale<=20, ma non sono disponibili indicazioni sul bug che a suo tempo si è voluto correggere con questo codice
		// Per risolvere rompendo meno possibile la compatibilità con il passato viene imposto il minimo a 1
		//a.maxScale -= 20;
		a.maxScale = Math.max(a.maxScale-20, 1); 
		
		this.selezioniLayer = new OpenLayers.Layer.Vector("Selezione", a );
	    
	    layerOptions.style = styleHighlighted;	    
	    this.evidenziazioniLayer = new OpenLayers.Layer.Vector("Evidenziazioni", layerOptions );
	    
	    layerOptions.style = styleAutoidentify;	    
	    autoIdentifiedLayer = new OpenLayers.Layer.Vector("AutoIdentify", layerOptions );	    
	    
	    layerOptions.style = undefined;  
	    layerOptions.styleMap= new OpenLayers.StyleMap({
		            "default": styleRouting,
		            "select": {
					 	strokeColor  : "red",
					    strokeOpacity: 1,
					    strokeWidth  : 2,
					    pointRadius  : 6,
					    pointerEvents: "visiblePainted",
					    fillColor    : "red",
					    fillOpacity  : 0.4
		            	}
		        });
	    
	    
	    this.routingLayer = new OpenLayers.Layer.Vector("Routing",  {
            styleMap:new OpenLayers.StyleMap({
                "default":new OpenLayers.Style(OpenLayers.Util.applyDefaults({                    
                    strokeColor:"#00FF00",                    
                    strokeWidth  : 2                    
                }, OpenLayers.Feature.Vector.style["default"])),
                "select":new OpenLayers.Style(OpenLayers.Util.applyDefaults({
                	strokeColor:"green",                    
                    strokeWidth  : 2
                }, OpenLayers.Feature.Vector.style["default"])),
                "temporary":new OpenLayers.Style(OpenLayers.Util.applyDefaults({
                	strokeColor:"red",                    
                    strokeWidth  : 2
                }, OpenLayers.Feature.Vector.style["highlight"]))

            })
        } );
	    
	    this.routingMarkersLayer = new OpenLayers.Layer.Vector("Routing markers", layerOptions);		        
	    
	    markersLayer = new OpenLayers.Layer.Markers( "Markers" );
	    
		elencoLayer.push(this.drawLayer);	  
		elencoLayer.push(this.routingLayer);
	    elencoLayer.push(this.routingMarkersLayer);	    
		elencoLayer.push(this.selezioniLayer); 
		elencoLayer.push(this.evidenziazioniLayer);
		elencoLayer.push(autoIdentifiedLayer);		
		
	    elencoLayer.push(markersLayer);
	    
		this.map.addLayers(elencoLayer);

		
	    var options = {handlerOptions: {freehand: false}};
	    
	    var optionsMeasure = {	    
	    	handlerOptions: {
	    		
	    		freehand: false, 
	    		sides: 40
	    	} 
	    };
		    
	    var autoIdentifyOptions = {
            'delay': 500,
            'pixelTolerance': 3,
            'stopMove': false
        };
        
        // Opzioni pointFromRef                                			    
	    var pointFromRefOptions = {callbacks : {
	    	'refPoint' : function(point){	    		
							me.fireEvent('onDrawFirstPointFromRef', point);																																	
					   },
		    'distance' : function(distance){													
							me.fireEvent('onDrawDistanceFromRefChange', distance);
					   }				   
	    }};
	    
	    // Opzioni constrained line 
	    var pointByCADOptions = {callbacks : {
	    	'firstPoint' : function(point){
							me.fireEvent('onDrawFirstPointByCAD', point);																												
					   },
		    'distance' : function(distance){													
							me.fireEvent('onDrawDistanceByCADChange', distance);
					   }				   
	    }, handlerOptions:{infoOnMouse: true}};
	    
	    // Opzioni constrained line 
	    var lineByCADOptions = {callbacks : {
	    	'firstPoint' : function(point){
							me.fireEvent('onDrawFirstPointByCAD', point);																												
					   },
		    'distance' : function(distance){													
							me.fireEvent('onDrawDistanceByCADChange', distance);
					   }				   
	    }, handlerOptions:{ring:false, infoOnMouse: true}};
	    
	    // Opzioni constrained polygon
	    var polygonByCADOptions = {callbacks : {
			'firstPoint' : function(point){
						       me.fireEvent('onDrawFirstPointByCAD', point);																														
						   },
		    'distance'   : function(distance){													
						       me.fireEvent('onDrawDistanceByCADChange', distance);
					       }
					       ,
			'aftermodify'     : function(point,sketch){	
						       var area = sketch.geometry.getArea();
						
							  //Arrotondamento a 2 decimali
							  area = Math.round(area*100)/100;										
							  me .fireEvent('onDrawAreaByCADChange', area);
							  return true;
					       }		   				   
	    }, handlerOptions:{infoOnMouse: true}};
	    
		var autoIdentify = new OpenLayers.Control();
		
		autoIdentify.handler = new OpenLayers.Handler.Hover(
			autoIdentify,
	        {
	        	'pause': function(e) { me.olAutoIdentifyOnPause(e); },
	        	'move' : function(e) { me.olAutoIdentifyOnMove(e); }
	        },
	        autoIdentifyOptions
	    )
	    
	    // OpenLayers.Renderer.symbol.crossNarrow = [8,0, 9,0, 9,8, 17,8, 17,9, 9,9, 9,17, 8,17, 8,9, 0,9, 0,8, 8,8, 8,0];
	    
	    var measurePointSymbolizer = {
            pointRadius: 6,
            graphicName: "cross",
            fillColor: "white",
            fillOpacity: 1,
            strokeWidth: .5,
            strokeOpacity: 1,
            strokeColor: "#333333"
        }
        
        var measureLineSymbolizer = {
            strokeWidth: 1.5,
            strokeOpacity: 1,
            strokeColor: "#666666",
            strokeDashstyle: "solid" //"longdashdot"
        }
        
        var measurePolygonSymbolizer =  {
            strokeWidth: 1.5,
            strokeOpacity: 1,
            strokeColor: "#666666",
            fillColor: "white",
            fillOpacity: 0.3
        }
        
        // Override by generic styleMeasure and by single symbolyzer
        measurePointSymbolizer   = OpenLayers.Util.extend(measurePointSymbolizer,this.styleMeasure || {});
	    measurePointSymbolizer   = OpenLayers.Util.extend(measurePointSymbolizer,this.measurePointSymbolizer || {});
	    measureLineSymbolizer    = OpenLayers.Util.extend(measureLineSymbolizer,this.styleMeasure || {});
	    measureLineSymbolizer    = OpenLayers.Util.extend(measureLineSymbolizer,this.measureLineSymbolizer || {});
	    measurePolygonSymbolizer = OpenLayers.Util.extend(measurePolygonSymbolizer,this.styleMeasure || {});
	    measurePolygonSymbolizer = OpenLayers.Util.extend(measurePolygonSymbolizer,this.measurePolygonSymbolizer || {});
	    
	    // style the sketch fancy
        var measureSymbolizers = {
            "Point"  : measurePointSymbolizer,
            "Line"   : measureLineSymbolizer,
            "Polygon": measurePolygonSymbolizer
        };
        
        var  style = new OpenLayers.Style();
        style.addRules([
            new OpenLayers.Rule({symbolizer: measureSymbolizers})
        ]);
        var styleMap = new OpenLayers.StyleMap({"default": style});
        
        // allow testing of specific renderers via "?renderer=Canvas", etc
        var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
        renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;
        
        var measureControls = {
            line: new OpenLayers.Control.Measure(
                OpenLayers.Handler.Path, {
                    persist: true,
                    immediate: true,
                    handlerOptions: {
                        layerOptions: {
                            renderers: renderer,
                            styleMap: styleMap
                        }
                    },
                    geodesic: true
                }
            ),
            polygon: new OpenLayers.Control.Measure(
                OpenLayers.Handler.Polygon, {
                    persist: true,
                    immediate: true,
                    handlerOptions: {
                        layerOptions: {
                            renderers: renderer,
                            styleMap: styleMap
                        }
                    },
                    geodesic: true
                }
            ),
            circle: new OpenLayers.Control.Measure(
                OpenLayers.Handler.RegularPolygon, {
                    persist: true,
                    immediate: true,
                    handlerOptions: {
                        layerOptions: {
                            renderers: renderer,
                            styleMap: styleMap
                        },
                        sides: 40
                    },
                    geodesic: true
                }
            )
        };
        
        for(var key in measureControls) {                
            measureControls[key].events.on({
                "measure": function(e){e.control = this; me.olHandleMeasurements(e,false)},
                "measurepartial": function(e){e.control = this; me.olHandleMeasurements(e,true)}
            });                
        }
        
        // Patch per risolvere problema dovuto a modifica delle dimenzioni della finestra, apertura debugger etc.
        // Quando centro e risoluzione non cambiano non vengono registrate variazioni nello stack di navigazione
        // ====== INIZIO PATCH
       	this.navh = new OpenLayers.Control.NavigationHistory (
	        	{
	        		listeners : {
	        			moveend : OpenLayers.Function.bind(function() {	        				
			                if(!this.navh.restoring) {
			                	
			                    var state = this.navh.registry['moveend'].apply(this.navh, arguments);
			                    
			                    if(this.navh.previousStack.length > 0 &&
			                       this.navh.previousStack[0].resolution == state.resolution &&
			                       this.navh.previousStack[0].center.lon == state.center.lon &&
			                       this.navh.previousStack[0].center.lat == state.center.lat) 
			                    {
			                		// Non registro nello stack della navigazione
			                		return true;
			                	}
			                	
			                    this.navh.previousStack.unshift(state);
			                    if(this.navh.previousStack.length > 1) {
			                        this.navh.onPreviousChange(
			                            this.navh.previousStack[1], this.navh.previousStack.length - 1
			                        );
			                    }
			                    if(this.navh.previousStack.length > (this.navh.limit + 1)) {
			                        this.navh.previousStack.pop();
			                    }
			                    if(this.navh.nextStack.length > 0) {
			                        this.navh.nextStack = [];
			                        this.navh.onNextChange(null, 0);
			                    }
			                }
			                return true;		              
			            },this)
	        		}
	        	}
	        );
	    
		this.navh.previous.events.register('activate', this, function(){this.fireEvent('previousNavigationStateAvailable');});
		this.navh.previous.events.register('deactivate', this, function(){this.fireEvent('previousNavigationStateNotAvailable');});
		this.navh.next.events.register('activate', this, function(){this.fireEvent('nextNavigationStateAvailable');});
		this.navh.next.events.register('deactivate', this, function(){this.fireEvent('nextNavigationStateNotAvailable');});
		// ===========  FINE PATCH
		
	    //{zoomBoxEnabled: true}
	    this.mapControls = {
	        navigation   : new OpenLayers.Control.Navigation(),
	        // N.B. Se alwaysZoom:true si verifica un bug che porta allo zoom non corretto (spostato e troppo ravvicinato) 
	        // solo quando si attiva lo strumento zoombox e non quando si fa shift-tasto muose
	        zoombox       : new OpenLayers.Control.ZoomBox({alwaysZoom:false, zoomOnClick: false}), 
	        vertexediting : new OpenLayers.Control.ModifyFeature(this.selezioniLayer, {standalone:true}),
	        dragdrop	  : new OpenLayers.Control.DragFeature(this.selezioniLayer),	        
	        measureLine   : measureControls['line'],
	        measurePolygon: measureControls['polygon'],                
	        measureCircle : measureControls['circle'],               	        
	        autoIdentify  : autoIdentify,
	        attribution   : new OpenLayers.Control.AttributionMulti(),
	        navhistory    : this.navh
		};
				 	    
	    // Se presenti più di una mappa inserisco anche il layerswitcher
	    if (this.paramsJS.mappe.mappaList.length>1) {
	    	this.mapControls.legend = new OpenLayers.Control.LayerSwitcher({activeColor: "#004000"});
	    }
	        
	    this.mapControls['dragdrop'].onComplete  = function (geom) { me.olViewerOnDragDropEnd(geom); }
	    
	    this.mapControlsDrawLayer = {
	    	point       : new OpenLayers.Control.DrawFeature(this.drawLayer, OpenLayers.Handler.Point),
	        pointFromRef: new OpenLayers.Control.DrawFeature(this.drawLayer, OpenLayers.Handler.PointFromRef,pointFromRefOptions),
	        pointByCAD  : new OpenLayers.Control.DrawFeature(this.drawLayer, OpenLayers.Handler.ConstrainedPoint,pointByCADOptions),
	        line        : new OpenLayers.Control.DrawFeature(this.drawLayer, OpenLayers.Handler.Path, options),
	        lineByCAD   : new OpenLayers.Control.DrawFeature(this.drawLayer, OpenLayers.Handler.ConstrainedPath,lineByCADOptions),
	        polygon     : new OpenLayers.Control.DrawFeature(this.drawLayer, OpenLayers.Handler.Polygon, options),
	        polygonByCAD: new OpenLayers.Control.DrawFeature(this.drawLayer, OpenLayers.Handler.ConstrainedPolygon,polygonByCADOptions),
	        modify      : new OpenLayers.Control.ModifyFeature(this.drawLayer),
	        dragdrop    : new OpenLayers.Control.DragFeature(this.drawLayer)   // , {mode: OpenLayers.Control.ModifyFeature.RESIZE | OpenLayers.Control.ModifyFeature.RESHAPE | OpenLayers.Control.ModifyFeature.DRAG }
	    };
	    
	    this.mapControlsDrawLayer['point'].events.register('featureadded', this, this.olViewerOnDigitizedPoint);
	    this.mapControlsDrawLayer['line'].events.register('featureadded', this, this.olViewerOnDigitizedLine);
	    this.mapControlsDrawLayer['polygon'].events.register('featureadded', this, this.olViewerOnDigitizedPolygon);
	    this.mapControlsDrawLayer['pointFromRef'].events.register('featureadded', this, this.olViewerOnDigitizedPointFromRef);
	    this.mapControlsDrawLayer['pointByCAD'].events.register('featureadded', this, this.olViewerOnDigitizedPointByCAD);
    	this.mapControlsDrawLayer['lineByCAD'].events.register('featureadded', this, this.olViewerOnDigitizedLineByCAD);
    	this.mapControlsDrawLayer['polygonByCAD'].events.register('featureadded', this, this.olViewerOnDigitizedPolygonByCAD);
	    
	    this.drawLayer.events.register('afterfeaturemodified', this, this.olViewerOnDigitizedFeatureVertexEditingEnd);
	    this.mapControlsDrawLayer['dragdrop'].onComplete  = function (geom) { me.olViewerOnDigitizedFeatureDragDropEnd(geom); }
	    
	    this.routingControlManager = Ext.create('TolomeoExt.ToloViewerOLPanel.SelectFeatureControlManager',
			{
				map: this.map,
				viewer: this	
									
			});	    
	    
	    var routingDragdropCtrl = new OpenLayers.Control.DragFeature(this.routingMarkersLayer);		   
	    routingDragdropCtrl.onComplete  = function (feature, pixel) { me.olViewerOnDragDropEndRouting(feature); };
	     	   	   
	    var routingDelegatorWidget = Ext.create('TolomeoExt.ToloViewerOLPanel.SelectFeatureControlManager.DelegatorWidget',{
	    	id : 'routing',
	    	layers : [this.routingLayer,this.routingMarkersLayer],
	    	callbacks : {
	    		onBeforeSelect : function(layerName, feature, viewer){return false;}, // per impedire la visualizazione della selezione		    		
		    	onHighlight : function(layerName,feature,viewer){viewer.fireEvent('routingInformationSelect', feature.attributes.instructionId);},
		    	onUnhighlight : function(layerName,feature,viewer){viewer.fireEvent('routingInformationUnSelect', feature.attributes.instructionId);}
	    	},
	    	moreControls : [routingDragdropCtrl]	    	
	    });
	    	    
	    this.routingControlManager.addDelegator(routingDelegatorWidget);	    

	    for(var key in this.mapControls) {
	        this.map.addControl(this.mapControls[key]);
	    }
	    
	    // @PATCH per evitare che tenendo premuto SHIFT faccia lo zoom 
	    // Sarebbe utile che Openlayers mettesse a disposizione un property zoomBoxOptions per il Navigation control, così come c'è la property
	    // pinchZoomOptions, invece di mettere a disposizione solo la proprietà zoomBoxKeyMask per impostare il codice del tasto con cui fare lo zoombox.
	    this.mapControls['navigation'].zoomBox.zoomOnClick = false;
	    
	    for(var key in this.mapControlsDrawLayer) {
	        this.map.addControl(this.mapControlsDrawLayer[key]);
	    }
	    	    
		var thisVar = this;
		
		this.map.events.register("zoomend", this, function(){ 
			this.fireEvent('scalechange', thisVar.pluginGetCurrentZoom());
		});
		
		this.map.events.register("preaddlayer", this, function(e){
			if(this.map.getLayer(e.layer.id)) return false;			
		});	
			
		
		this.olViewerToolSelectSelectEventHandler = function(e,visualize){				
			var lonlat = this.map.getLonLatFromViewPortPx(e.xy);
			var selMode = null;
			if (e.shiftKey) {
				selMode = (this.paramsJS.selectDefaultMode=='FIRSTONTOP') ?  'allStacked':'firstOnTop';
			} else {
				selMode = (this.paramsJS.selectDefaultMode=='FIRSTONTOP') ?  'firstOnTop' : 'allStacked';
			}
			
			this.fireEvent('onMappaSelect', new Point(lonlat.lon, lonlat.lat),selMode,e.ctrlKey,e.altKey, e.xy.x, e.xy.y);
						//OpenLayers.Event.stop(e);				
		}
		////////////////////////////////////////
		// Impostazione dei layer di snapping //
		////////////////////////////////////////
		this.snapControls = [];
		var snappedMapLayers = [this.selezioniLayer,this.drawLayer];
		
		for(var evtLi = 0; evtLi < this.paramsJS.azioniEventi.eventiLayerList.length; evtLi++){
			
			var evtL = this.paramsJS.azioniEventi.eventiLayerList[evtLi];
			
			if(evtL.snapping && evtL.snapping.snappingLayerList && evtL.snapping.snappingLayerList.length > 0){
								
				var targetList = [];
				var wfsLayerList = [];
				
				for(var sLi = 0; sLi < evtL.snapping.snappingLayerList.length; sLi++){
					
					var snappingLayer = evtL.snapping.snappingLayerList[sLi];
					
					var wfsLayer = new OpenLayers.Layer.Vector(snappingLayer.name,
					{
						style: styleSnap,
						minScale : snappingLayer.minScale,
						maxScale : snappingLayer.maxScale,
						strategies: [new OpenLayers.Strategy.BBOX()],
						projection: new OpenLayers.Projection(snappingLayer.srsName),
						protocol: new OpenLayers.Protocol.WFS({
							url: snappingLayer.url  + (snappingLayer.role ? ((snappingLayer.url.indexOf("?")==-1 ? "?" : "&" ) + "role="+snappingLayer.role) :""),		
							featureType: snappingLayer.featureType.split(","),		
							srsName: snappingLayer.srsName,
							version: "1.1.0",		
							featureNS: snappingLayer.featureNS ? snappingLayer.featureNS : null,
							featurePrefix: snappingLayer.featurePrefix ? snappingLayer.featurePrefix : null,
							propertyNames: snappingLayer.propertyNames ? snappingLayer.propertyNames.split(",") : null,
							geometryName: snappingLayer.geometryName,
							outputFormat: "JSON"
						}),
						visibility : false,
						isBaseLayer : false,
						eventListeners : {
							'loadend': function(e){
								if(e.object.features.length == 0){
									Ext.Msg.alert(ToloI18n.getMsg("ToloViewerOLPanel.pluginPreInit.caricSnap.msg"),ToloI18n.getMsg("ToloViewerOLPanel.pluginPreInit.caricSnap.msg"));
								}
							},
							scope: this
						}
					});
					
					/*
					if(snappingLayer.role){
						var newParam = {role: snappingLayer.role};
						wfsLayer.mergeNewParams(newParam);
					}
					*/
					
					wfsLayerList.push(wfsLayer);
					
					targetList.push({
						layer: wfsLayer,
						tolerance: snappingLayer.tolerance,
						edge: snappingLayer.edge
						//filter: new OpenLayers.Filter.Comparison({
				        //    type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO,
				        //    property: "surface",
				        //    value: "dirt"
				        //})
					});
					
				}
				
				this.map.addLayers(wfsLayerList);
				var layerMapSnapControls = [];
				
				for (var sml=0; sml < snappedMapLayers.length; sml++){
					var snapControl = new OpenLayers.Control.Snapping({					
						layer: snappedMapLayers[sml],					
						targets: targetList,
						greedy: false,
						eventListeners: {
							// fa in modo di non snappare se il layer non è visibile o si è fuori dal range di scale previsto
							"beforesnap" : function(evt){		
								return evt.layer.getVisibility() && evt.layer.calculateInRange();	
							},
							scope: this
						}
					});
					
					snapControl.layerList = wfsLayerList;
					layerMapSnapControls.push(snapControl);
					
					this.map.addControl(snapControl);
				}
				/*
				// fa in modo di non snappare se il layer non è visibile o si è fuori dal range di scale previsto
				snapControl.events.register("beforesnap", this, function(evt){		
					return evt.layer.getVisibility() && evt.layer.calculateInRange();	
				});
				*/
				
				this.snapControls[evtL.codTPN] = layerMapSnapControls;				
				
				// snapControl.activate();
			}	
		}	   
								
	   this.isAlreadyDrawn = false;
	   this.fireEvent("onAfterPreInit");
	},

	pluginShowTimeMachine: function(show) {
		if (show) {
			// TODO  generalizzare adesso considera solo mappa[0] gestisce solo prima mappa
			if (this.timeMachinePanel==null && (this.paramsJS.mappe.mappaList[0].timeMachineList!=null && this.paramsJS.mappe.mappaList[0].timeMachineList.length>0)) {
		        var pnl = null;
				if (this.paramsJS.mappe.mappaList[0].timeMachineList.length==1) {
					pnl = new TolomeoExt.ToloTimeMachinePanel({
						viewer: this,
						paramsJS: this.paramsJS,
						timeMachineToShow: 0,
						cls: 'clsTimeMachinePanel'
					});
					
				} else {
					pnl = new TolomeoExt.ToloTimeMachineMultiPanel({
						viewer: this,
						paramsJS: this.paramsJS,
						timeMachineToShow: 0,
						cls: 'clsTimeMachinePanel'
					});
				}
			
	        	this.timeMachinePanel = new Ext.Window({
	        		//title: "",  
					layout: 'fit',
					maximizable: true,
					constrain: true,
					collapsible: true,
					border: false,
					shadow: false,
					height: 270,
					width: 370,
					autoScroll: true,
					//constrainTo: this.body,
					//renderTo: this.body,
					liveDrag: true,
					items: [pnl],
					cls: 'clsTimeMachineWindow'
				}).show();
	    
	        		
	        	//this.add(this.timeMachinePanel);
	        	this.timeMachinePanel.show(this);
	        	this.timeMachinePanel.on('close', function() {this.timeMachinePanel = null;this.fireEvent("onTimeMachineHide");}, this);
	        	
	        	if (this.paramsJS.mappe.mappaList[0].timeMachineList.length==1) {
	        		pnl.calculateAutoOffset();
	        		pnl.reloadItems();
	        	}
	        	//pnl.a.calculateAutoOffset();
	        	//pnl.a.reloadItems();
	        	
	        	//pnl.calculateAutoOffset();
	        	//pnl.reloadItems();
	        	
	        	this.fireEvent("onTimeMachineShow");
		   	} 
		}  else {
		   if (this.timeMachinePanel)  {
			   
			   this.timeMachinePanel.close();
			   this.remove(this.timeMachinePanel);
			   this.fireEvent("onTimeMachineHide");
			   //this.timeMachinePanel = null;
			// this.timeMachinePanel.hide(this);
		   }
	    }
	},
	
	/**
	 * Method: pluginMeasureClear
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginMeasureClear: function() {
		this.fireEvent('onMeasureClear');
	},
	
	/**
	 * Method: pluginMeasureStop
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginMeasureStop: function() {
		this.pluginMeasureClear();
		this.deactivateControl('measurePolygon');
		this.deactivateControl('measureCircle');
		this.deactivateControl('measureLine');
		this.fireEvent('onMeasureStop');
	},

	/**
	 * Method: pluginSetLegendWidth
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginSetLegendWidth : function () {},

	pluginStartDigitizedFeatureModify: function(mode) {
		
		switch (mode) {
			case 0: // niente da fare
				break;
			case 1: this.activateControlDrawLayer('modify');
				break;
			case 2: this.activateControlDrawLayer('dragdrop');
				break;	
		}

	},
	
	pluginStopDigitizedFeatureModify: function(mode) {

		switch (mode) {
			case 0: // niente da fare
				break;
			case 1: this.deactivateControlDrawLayer('modify');
				break;
			case 2: this.deactivateControlDrawLayer('dragdrop');
				break;	
		}
		
	},
	
	/**
	 * Method: pluginStartDigitizePoint
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDigitizePoint: function () {
		this.activateControlDrawLayer('point');
	},
	
	/**
	 * Method: pluginStopDigitizePoint
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDigitizePoint: function () {
		this.deactivateControlDrawLayer('point');				
	},
	
	/**
	 * Method: pluginStartDigitizePointFromRef
	 * Funzione che inizia la digitalizzazione (disegno) di un punto con la modalità CAD
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDigitizePointFromRef: function () {
		this.activateControlDrawLayer('pointFromRef');
	},
	
	/**
	 * Method: pluginStopDigitizePointFromRef
	 * Funzione che interrompe la digitalizzazione (disegno) di un punto con la modalità CAD
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDigitizePointFromRef: function () {		
		this.deactivateControlDrawLayer('pointFromRef');
		this.fireEvent('onDigitizePointFromRefEnd');		
	},
	
	/**
	 * Method: pluginStartDigitizeLineByCAD
	 * Funzione che inizia la digitalizzazione (disegno) di una linea con la modalità CAD
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDigitizePointByCAD: function () {
		this.cadPanel.on('pressSetCommand',this.runCommandOnPointByCAD, this)
		this.cadPanel.on('changeAngleSetting',this.setRelativeAngleOnPointByCAD, this);
		this.cadPanel.on('pressDeleteFirstLine',this.delFirstLineOnPointByCAD, this);
		this.activateControlDrawLayer('pointByCAD');
	},
			
	/**
	 * Method: pluginStartDigitizeLineByCAD
	 * Funzione che interrompe la digitalizzazione (disegno) di una linea con la modalità CAD
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDigitizePointByCAD: function () {
		this.cadPanel.un('pressSetCommand',this.runCommandOnPointByCAD, this)
		this.cadPanel.un('changeAngleSetting',this.setRelativeAngleOnPointByCAD, this);
		this.cadPanel.un('pressDeleteFirstLine',this.delFirstLineOnPointByCAD, this);
		this.deactivateControlDrawLayer('pointByCAD');
		this.fireEvent('onDigitizePointByCADEnd');
		
	},		
	
	/**
	 * Method: pluginStartDigitizeLineByCAD
	 * Funzione che inizia la digitalizzazione (disegno) di una linea con la modalità CAD
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDigitizeLineByCAD: function () {
		this.cadPanel.on('pressSetCommand',this.runCommandOnLineByCAD, this)
		this.cadPanel.on('changeAngleSetting',this.setRelativeAngleOnLineByCAD, this);
		this.cadPanel.on('pressDeleteFirstLine',this.delFirstLineOnLineByCAD, this);
		this.activateControlDrawLayer('lineByCAD');
	},
			
	/**
	 * Method: pluginStartDigitizeLineByCAD
	 * Funzione che interrompe la digitalizzazione (disegno) di una linea con la modalità CAD
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDigitizeLineByCAD: function () {
		this.cadPanel.un('pressSetCommand',this.runCommandOnLineByCAD, this)
		this.cadPanel.un('changeAngleSetting',this.setRelativeAngleOnLineByCAD, this);
		this.cadPanel.un('pressDeleteFirstLine',this.delFirstLineOnLineByCAD, this);
		this.deactivateControlDrawLayer('lineByCAD');
		this.fireEvent('onDigitizeLineByCADEnd');
		
	},		
	
	/**
	 * Method: pluginStartDigitizePolygonByCAD
	 * Funzione che inizia la digitalizzazione (disegno) di un poligono con la modalità CAD
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDigitizePolygonByCAD: function () {
		this.cadPanel.on('pressSetCommand',this.runCommandOnPolygonByCAD, this)
		this.cadPanel.on('changeAngleSetting',this.setRelativeAngleOnPolygonByCAD, this);
		this.cadPanel.on('pressDeleteFirstLine',this.delFirstLineOnPolygonByCAD, this);
		this.activateControlDrawLayer('polygonByCAD');
	},
	
	/**
	 * Method: pluginStartDigitizePolygonByCAD
	 * Funzione che interrompe la digitalizzazione (disegno) di un poligono con la modalità CAD
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDigitizePolygonByCAD: function () {
		this.cadPanel.un('pressSetCommand',this.runCommandOnPolygonByCAD, this)
		this.cadPanel.un('changeAngleSetting',this.setRelativeAngleOnPolygonByCAD, this);
		this.cadPanel.un('pressDeleteFirstLine',this.delFirstLineOnPolygonByCAD, this);
		this.deactivateControlDrawLayer('polygonByCAD');
		this.fireEvent('onDigitizePolygonByCADEnd');		
	},		
		
	/**
	 * Method: pluginStartDigitizeLine
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDigitizeLine: function () {
		this.activateControlDrawLayer('line');
	},
	
	/**
	 * Method: pluginStopDigitizeLine
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDigitizeLine: function () {
		this.deactivateControlDrawLayer('line');
	},

	/**
	 * Method: pluginStartDigitizePolygon
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDigitizePolygon: function () {				
		this.activateControlDrawLayer('polygon');
	},
	
	/**
	 * Method: pluginStopDigitizePolygon
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDigitizePolygon: function () {
		this.deactivateControlDrawLayer('polygon');
	},

	/**
	 * Method: pluginStartDigitizeCircle
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDigitizeCircle: function () {},

	/**
	 * Method: pluginStopDigitizeCircle
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDigitizeCircle: function () {},
	
	/**
	 * Method: pluginStartVertexEditing
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartVertexEditing: function (geomType, codTPN) {			
		this.selezioniLayer.events.register('afterfeaturemodified', this, this.olViewerOnVertexEditingEnd);
				
		this.activateControl('vertexediting');

		//this.mapControls['vertexediting'].selectControl.select(this.selezioniLayer.features[0]);
		var currentCodTPN = codTPN;
		for(var i=0; i < this.selezioniLayer.features.length; i++){
			if(this.selezioniLayer.features[i].codTPN == currentCodTPN){				
				//this.mapControls['vertexediting'].selectControl.select(this.selezioniLayer.features[i]);
				this.mapControls['vertexediting'].selectFeature(this.selezioniLayer.features[i]);
				break;
			}
		}
	},

	/**
	 * Method: pluginStopVertexEditing
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopVertexEditing: function () {
		this.selezioniLayer.events.unregister('afterfeaturemodified', this, this.olViewerOnVertexEditingEnd);
		this.deactivateControl('vertexediting');
	},

	/**
	 * Method: pluginStartDragDrop
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStartDragDrop: function (geomType) {			
		this.firstSelectionPermitted = false;		
		this.activateControl('dragdrop');		
	},
	
	/*
	 * Method: pluginStopDragDrop
	 * Funzione che inizia la digitalizzazione (disegno)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginStopDragDrop: function (geomType) {
		this.deactivateControl('dragdrop');
	},

	/**
	 * Method: pluginDigitizeLayerClear
	 * Funzione che cancella gli oggetti presenti sul layer utilizzato per la digitalizzazione
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginDigitizeLayerClear: function (){
		this.drawLayer.destroyFeatures();
	},

	/**
	 * Method: pluginToolSelectZoomIn
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectZoomIn: function() {
		this.map.zoomIn();
		//if(this.map.getScale()<this.paramsJS.mappe.maxScale){this.map.zoomToScale(this.paramsJS.mappe.maxScale);}
	},

	pluginToolSelectZoomOut: function()  {this.map.zoomOut();},
	
	/**
	 * Method: pluginToolSelectZoomPrev
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le pluginToolSelectZoomOut: function() {this.map.zoomOut();}, plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectZoomPrev: function() {},
	
	/**
	 * Method: pluginToolSelectZoomAll
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectZoomAll: function() {this.map.zoomToMaxExtent();},
	
	/**
	 * Method: pluginToolSelectZoomBox
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectZoomBoxActivate: function (activate) {
											this.activateControl('zoombox');
											},
	pluginToolSelectZoomBoxDeactivate: function (activate) {this.deactivateControl('zoombox')},
	
	/**
	 * Method: pluginToolSelectPan
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectPan: function () {this.activateControl('navigation');},
	
	/**
	 * Method: pluginToolSelectPanStop
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectPanStop: function () {/*this.deactivateControl('navigation');*/},
	
	/**
	 * Method: pluginToolSelectPrint
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectPrint: function () 	{
		var urlArr = [];
		for (var i=0; i<this.map.layers.length; i++) {
			var currLayer = this.map.layers[i];
			if (currLayer.getVisibility() &&
					((currLayer.CLASS_NAME.indexOf("MapServer")!=-1) || (currLayer.CLASS_NAME.indexOf("WMS")!=-1))) {
					var typeCode = (currLayer.CLASS_NAME.indexOf("MapServer")!=-1) ? 0 : 11;
					urlArr.push({url: currLayer.getURL(currLayer.getExtent()), nPluginLayer: i, typeCode: typeCode });	
			}
			
		}
		//this.map.layers[0].getURL(this.map.layers[0].getExtent())
		this.fireEvent('onPrintMap', urlArr);
			
	},
		
	/**
	 * Method: pluginToolSelectClipboardCopy
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectClipboardCopy: function () 	{},
		
	/**
	 * Method: pluginToolSelectSelect
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectSelect: function () 	{
		//modificato da click a mouseup perch? click non funzionava correttamente in ie
		//da fare meglio e verificare su ie che ha comportamento diverso da firefox
				
		// this.map.events.register("click", this, this.olViewerToolSelectSelectEventHandler);						
		
		if(!this.selectHandler){
			var me = this;
			// usato per evitare l'evento click sul pan della geometria
			me.firstSelectionPermitted = true;
			this.selectHandler = new OpenLayers.Handler.Click(this.mapControls['navigation'], 
				{'click' : function(e){
						if(me.firstSelectionPermitted){
							me.olViewerToolSelectSelectEventHandler.call(me,e);
						} else {
							me.firstSelectionPermitted = true;
						}
					}
				}/*, {stopSingle : true}*/ );
		}
		
		this.selectHandler.activate();
			 
	},
	
	
	
	/**
	 * Method: pluginToolSelectSelectStop
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectSelectStop: function () 	{
		//modificato da click a mouseup perch? click non funzionava correttamente in ie
		//da fare meglio e verificare su ie che ha comportamento diverso da firefox
		/*
		this.map.events.unregister("click", this, this.olViewerToolSelectSelectEventHandler);		
		this.selectKeymapIn.disable();
		this.selectKeymapOut.disable();
		*/
		if(this.selectHandler){
			this.selectHandler.deactivate();
		}
	},
	
	/**
	 * Method: pluginMeasureToolSelect
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginMeasureToolSelect: function (tipo) 	{ 
		var controlName = "";
		switch (tipo) {
			case 0: controlName = 'measurePolygon'; 
				break;
			case 1: controlName = 'measureCircle'; 
				break;
			case 2: controlName = 'measureLine'; 
				break;	
		}
		
		this.activateControl(controlName);
		this.fireEvent('onMeasureStart', tipo);
	},
	
	/**
	 * Method: pluginToolSelectBuffer
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectBuffer: function () {},
	
	/**
	 * Method: pluginToolSelectInfoMappa
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectInfoMappa: function () {},
	
	/**
	 * Method: pluginToolSelectLegendaToggle
	 * Funzione per la gestione "tool" (zoom, pan etc)
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginToolSelectLegendaToggle: function (larghezza) {},

	/**
	 * Method: pluginGotoPosition
	 * Funzione di posizionamento della mappa
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 */
	pluginGotoPosition: function (coordX, coordY, zoomFactor, withMarker, iconPath) {  
		var res = OpenLayers.Util.getResolutionFromScale(zoomFactor, this.map.baseLayer.units);
		var lonlat = new OpenLayers.LonLat(coordX,coordY);
		this.map.setCenter(lonlat, this.map.getZoomForResolution(res), false, true);
		this.isAlreadyDrawn=true;
		if (withMarker) this.pluginAddMarker(coordX, coordY,iconPath,true);
	},

	/**
	 * Method: pluginGetSelectedKeys
	 * Funzione di selezione oggetti.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer
	 *
	 * Parameters:
	 * layerName - {String} layerName.
	 *
	 * Returns:
	 *    {Array} - ritorna un Array contenente le chiavi degli oggetti correntemente selezionati ed appartenenti a layerName.
	 *    N.B. Non è stata fatta una funzione che ritorna tutti gli oggetti 
	 *    perchè un oggetto potrebbe essere in un gruppo che ha il nome del layer ma che viene tematizzato più volte con nomi diversi
	 */
	pluginGetSelectedKeys: function  (layerName) {
			var retVal = new Array();
			//TODO
			return retVal;
	},

	/**
	 * Ritorna la url dalla quale è ricavata l'immagine relativa al layer attualmente visualizzato utilizzando il bound passato
	 * 
	 * @param bounds - bounds che identificano la zona da mostrare nella forma  {left: bounds.left, bottom: bounds.bottom, right: bounds.right, top: bounds.top} 
	 * 
	 */
	pluginGetMapUrl: function(bounds) {
		
		var bounds = new OpenLayers.Bounds(bounds.left, bounds.bottom, bounds.right, bounds.top);
		
		return this.map.baseLayer.getURL(bounds);
		
	},
	
	/**
	 * Method: pluginRefreshMap
	 * Funzione per ridisegnare la mappa.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *	
	 * Parameters:
	 * layers 		- nomi layer separati dal separatore
	 * stili  		- nomi stili separati dal separatore
	 * separatore  	- separatore (default ' ')
	 * nLayer	    - numero del layer sul quale fare il refresh
	 */
	pluginRefreshMap: function (layers, stili, separatore, nLayer) {
		
		var sep = separatore ? separatore : ' '; 
		
		if (arguments.length==0) {
			for(var index=0; index<this.map.layers.length; index++) {
				var currLayer = this.map.layers[index];
				if (currLayer.getVisibility()==true) {
					if (currLayer.CLASS_NAME.indexOf("MapServer")!=-1 ||
						currLayer.CLASS_NAME.indexOf("WMS")!=-1	) {
							currLayer.mergeNewParams({random: Math.random()});
					} else {
						if (currLayer.redraw) currLayer.redraw();
					}
				}
			}
		} else {
			for(var index=0; index<this.map.layers.length; index++) {
				if ((nLayer==undefined || nLayer==null) ||
					(nLayer!=undefined && nLayer!=null && nLayer==index)) {
					var currLayer = this.map.layers[index];
					
					if (currLayer.CLASS_NAME.indexOf("MapServer")!=-1) {
						// in caso di layer mapserver 
						// fatto cosÌ su consiglio di openlayers dopo avere aperto bug 
						// perchè la cache del browser non ricaricava e non sentiva la differenza.
						// Andrebbe fatto leggermente più intelligente per ricaricare solo i layer cambiati
						
						
						if (layers != undefined && layers!=null) {
							if (layers=="") {
								currLayer.setVisibility(false);
							} else {
								var opt = new Object();
								opt.random= Math.random();
							
								var buff = layers;
								if (sep!=' ') {
									// sostituisce il separatore con quello giusto per Mapserver
									var pattern = new RegExp(sep,'g');
									buff = buff.replace(pattern, ' ');
								}
								opt.layers=buff;
								currLayer.mergeNewParams(opt);
								currLayer.setVisibility(true);
							}
						}
					} else {
						if (currLayer.CLASS_NAME.indexOf("WMS")!=-1) {
							
							if (layers != undefined && layers!=null) {
								if (layers=="") {
									currLayer.setVisibility(false);
								} else {
									var opt = new Object();
									opt.random= Math.random();
									var buff = layers;
									if (sep!=',') {
										// sostituisce il separatore con quello giusto per WMS
										var pattern = new RegExp(sep,'g');
										buff = buff.replace(pattern, ',');
									} 
									opt.layers=buff;
									opt.styles='';
									if (stili) {
										var buff = stili;
										if (sep!=',') {
											// sostituisce il separatore con quello giusto per WMS
											var pattern = new RegExp(sep,'g');
											buff = buff.replace(pattern, ',');
										}
										opt.styles = buff
									}
									currLayer.mergeNewParams(opt);
									currLayer.setVisibility(true);
								}
							}
						} else {
						if (currLayer.redraw) currLayer.redraw();
						}
					}
				}	
			}	
		}
		
		this.pluginRefreshAttribution();
	},
	
	/**
	 * Method: pluginRefreshAttribution
	 * Funzione per aggiornare le attribuzioni di un layer.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *	
	 * Parameters:
	 * Attribution - {Object|Object[]}  Oggetto o array contenente le attribuzioni ognuna delle quali caratterizzata con in campi title, logoUrl, OnlineResource
	 */
	pluginRefreshAttribution: function(attribution, nPluginLayer) {
		if (attribution) {
			this.map.layers[nPluginLayer].attribution = attribution;
		}
		this.mapControls.attribution.updateAttribution();
		
	},
	
	//function pluginRefreshMapAndGoto(coordX, coordY, zoomFactor) {};
	
	/**
	 * Method: pluginRefreshLayer
	 * Funzione per ridisegnare il layer.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *	
	 * Parameters:
	 * layerName - {String} layerName
	 */
	pluginRefreshLayer: function (layerName) {
		// implementato con un refresh totale
	 	this.pluginRefreshMap() ;
	},

	/**
	 * Method: pluginGetMapExtent
	 * Ritorna l'extent del layer di base attualmente attivo
	 *
	 * Returns:
	 *    	Ritorna l'estensione totale della mappa  in un oggetto {left: bounds.left, bottom: bounds.bottom, right: bounds.right, top: bounds.top} 
	 */  
	pluginGetMapExtent: function () {
		bounds = this.map.baseLayer.getExtent();
		
		return {left: bounds.left, bottom: bounds.bottom, right: bounds.right, top: bounds.top};
		
	},
	
	/**
	 * Method: pluginGetMapFullExtent
	 * Ritorna l'extent del layer di base attualmente attivo compreso l'eventuale aggiunta ai bordi dovuta a ratio
	 *
	 * Returns:
	 *    	Ritorna l'estensione totale della mappa  in un oggetto {left: bounds.left, bottom: bounds.bottom, right: bounds.right, top: bounds.top}
	 */  
	pluginGetMapFullExtent: function(){
		
		var bounds = this.pluginGetMapExtent();
		var ratio = this.pluginGetMapRatio();
		
		  //determine new tile bounds
	    var center = { lon: bounds.left + (bounds.right - bounds.left) / 2,
	    			   lat: bounds.bottom + (bounds.top - bounds.bottom) / 2};
	    
	    var boundsWidth = (bounds.right - bounds.left) * ratio;
	    var boundsHeight = (bounds.top - bounds.bottom) * ratio;
	        
	    var fullBounds = 
	        new OpenLayers.Bounds(center.lon - (boundsWidth/2),
	                              center.lat - (boundsHeight/2),
	                              center.lon + (boundsWidth/2),
	                              center.lat + (boundsHeight/2));
	    
		return {left: fullBounds.left, bottom: fullBounds.bottom, right: fullBounds.right, top: fullBounds.top};
	},

	/**
	 * Method: pluginGetCurrentX
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Returns:
	 *    	Ritorna il valore corrente del centro della mappa visualizzata.
	 */ 
	pluginGetCurrentX: function () { return this.map.getCenter().lon; },
	
	/**
	 * Method: pluginGetCurrentY
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Returns:
	 *    	Ritorna il valore corrente del centro della mappa visualizzata.
	 */ 
	pluginGetCurrentY: function () { return this.map.getCenter().lat; },

	/**
	 * Method: pluginGetCurrentZoom
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Returns:
	 *    	Ritorna il valore corrente dello zoom della mappa visualizzata.
	 */ 
	pluginGetCurrentZoom: function () { return this.map.getScale(); },

	/**
	 * Method: pluginGetResolution
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer
	 *
	 * Returns:
	 *    	Ritorna la risoluzione attuale (map units per pixel) della mappa
	 */ 
	pluginGetResolution: function () { return this.map.getResolution(); },

	/**
	 * 
	 * @param {} scala
	 * @param {} unita
	 */
	pluginGetResolutionFromScale: function (scala, unita) { return OpenLayers.Util.getResolutionFromScale(scala, unita); },
	
	/**
	 * Method: pluginGetSRID
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer
	 *
	 * Returns:
	 *    	Ritorna il sistema di riferimento (map units per pixel) della mappa
	 */ 
	pluginGetSRID: function () { return this.paramsJS.mappe.SRID;},
	
	/**
	 * Method: pluginGetUnits
	 * come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer
	 * 
	 * Returns:
	 *    	Ritorna il sistema di unità della mappa
	 */
	pluginGetUnits: function () { return this.paramsJS.mappe.units;},
	
	/**
	 * 
	 * Returns:
	 *    	Ritorna true se l'unita usata dalla mappa è in gradi altrimenti false
	 */
	isDregreesUnits: function() {
		units = this.pluginGetUnits();
		if (units=="dd" || units=="degrees")
			return true;
		else
			return false;
	},
	
	/**
	 * 
	 * Returns:
	 *    	Ritorna true se l'unita usata dalla mappa è in metri o kilometri altrimenti false
	 */
	isMetresUnits: function() {
		units = this.pluginGetUnits();
		if (units=="m" || units=="km")
			return true;
		else
			return false;
	},

	/**
	 * Method: pluginGetDotsPerInch
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer
	 *
	 * Returns:
	 *    	Ritorna i dots per inch utilizzati dalla mappa
	 */ 
	pluginGetDotsPerInch: function() {
		return OpenLayers.DOTS_PER_INCH;
	},
	
	/**
	 * Method: pluginSetDotsPerInch
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer
	 * 
	 * @param {} dpi
	 */
	pluginSetDotPerInch: function(dpi) {
		OpenLayers.DOTS_PER_INCH = dpi;
	},
	
	/**
	 * Method: pluginAddSelected
	 * Funzione che viene chiamata per aggiungere un oggetto geometrico a quelli selezionati
	 * Per adesso solo un oggetto e' selezionabile, quindi cancella eventuali oggetto selezionati in precedenza.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 * 
	 * Parameters:
	 * jsGeometry - {} jsGeometry
	 * style - {} style
	 * 
	 */ 
	pluginAddSelected: function (jsGeometry, style) {
		var wkt = new OpenLayers.Format.WKT();
		var feature = wkt.read(jsGeometry.geometry);
		feature.codTPN = jsGeometry.codTPN;
		if (style) feature.style = style;
		this.selezioniLayer.addFeatures([feature]);
	},

	/**
	 * Method: pluginClearSelected
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 *	Returns:
	 *  {Boolean}
	 */ 
	pluginClearSelected: function (bRedraw, codTPN) {
		if (codTPN) {
			var buff=new Array();
			for (var i=0;i<this.selezioniLayer.features.length;i++) {
				if (this.selezioniLayer.features[i].codTPN == codTPN) buff.push(this.selezioniLayer.features[i]); 
			}
			for (var i=0;i<buff.length;i++) {
				 this.selezioniLayer.destroyFeatures(buff); 
			}
		} else {
			// non viene gestito bRedraw perche' in questo viewer la cancellazione non richiede il ridisegno
		    this.selezioniLayer.destroyFeatures();  
		}
		// ritorna sempre false perch? il redraw non e' mai necessario
		return false;
	},

	/**
	 * Method: pluginZoomToSelected
	 * Esegue lo zoom to selected.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * zoom - {Number} zoom, se valorizzato viene fatto lo zoom alla data scala
	 * buffer - {Number} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	pluginZoomToSelected: function (zoom, buffer) {
			//var bounds = this.selezioniLayer.features[0].geometry.getBounds();
		if(!(this.selezioniLayer.features && this.selezioniLayer.features.length>0)) return;
		var bounds = this.olGetExtents(this.selezioniLayer.features);
		if (!zoom) {
			if (buffer && this.isMetresUnits()) {
				var boundsBuffered = new OpenLayers.Bounds();
			    boundsBuffered.extend(new OpenLayers.LonLat(bounds.left-buffer/2,bounds.bottom-buffer/2));
			    boundsBuffered.extend(new OpenLayers.LonLat(bounds.right+buffer/2,bounds.top+buffer/2));
			    this.map.zoomToExtent(boundsBuffered);
			} else {
				if (bounds.top==bounds.bottom && bounds.right==bounds.left) {
					var lonLat = bounds.getCenterLonLat();
					this.pluginGotoPosition(lonLat.lon, lonLat.lat, this.paramsJS.mappe.maxScale, false);
				} else {
					this.map.zoomToExtent(bounds);
				}
			}
		} else {
			var lonLat = bounds.getCenterLonLat();
			this.pluginGotoPosition(lonLat.lon, lonLat.lat, zoom, false);	
		}
		this.isAlreadyDrawn=true;
	},
	
	/**
	 * @method pluginGetSelectedFeaturesBounds
	 * Restituisce il bounding box delle features selezionate compreso il buffer se passato in metri.
	 * Null se non ci sono features.
	 * 
	 * @param {String} buffer
 	 * Codice EPSG del sistema di riferimento di partenza (Es. EPSG:26591) 
 	 * 
	 * @return {TolomeoExt.BBox}
	 * Bounding box delle features selezione compreso il buffer se passato in metri
	 * 
	 */
	pluginGetSelectedFeaturesBounds: function(buffer){
		if(!(this.selezioniLayer.features && this.selezioniLayer.features.length>0)) return null;
		var bounds = this.olGetExtents(this.selezioniLayer.features);
		if(buffer && this.isMetresUnits()){
			var boundsBuffered = new OpenLayers.Bounds();
		    boundsBuffered.extend(new OpenLayers.LonLat(bounds.left-buffer/2,bounds.bottom-buffer/2));
		    boundsBuffered.extend(new OpenLayers.LonLat(bounds.right+buffer/2,bounds.top+buffer/2));
		    return BBox.create(boundsBuffered);
		}
		return new BBox.create(bounds);
	},	
	
	/**
	 * @method pluginGetHighlightedFeaturesBounds
	 * Restituisce il bounding box delle features evidenziate compreso il buffer se passato in metri.
	 * Null se non ci sono features.
	 * 
	 * @param {String} buffer
 	 * Codice EPSG del sistema di riferimento di partenza (Es. EPSG:26591) 
 	 * 
	 * @return {TolomeoExt.BBox}
	 * Bounding box delle features selezione compreso il buffer se passato in metri
	 * 
	 */
	pluginGetHighlightedFeaturesBounds: function(buffer){				
		if(!(this.evidenziazioniLayer.features && this.evidenziazioniLayer.features.length>0)) return null;
		var bounds = this.olGetExtents(this.evidenziazioniLayer.features);
		
		if(buffer && this.isMetresUnits()){
			var boundsBuffered = new OpenLayers.Bounds();
		    boundsBuffered.extend(new OpenLayers.LonLat(bounds.left-buffer/2,bounds.bottom-buffer/2));
		    boundsBuffered.extend(new OpenLayers.LonLat(bounds.right+buffer/2,bounds.top+buffer/2));
		    return BBox.create(boundsBuffered);
		}
		return new BBox.create(bounds);
	},
	
	/**
	 * Method: pluginAddHighlighted
	 * Funzione che viene chiamata per aggiungere un oggetto geometrico a quelli selezionati.
	 * Se bMulti non definito o false un solo oggetto e' evidenzxiabile, quindi cancella eventuali oggetto selezionati in precedenza
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer.
	 *
	 * Parameters:
	 * jsGeometry - {JSGeometryArray o JSGeometry} Oggetto da evidenziare, se passato un JSGeometryArray viene utilizzato il primo
	 * bMulti - {Boolean} bMulti Se non definito o false non è consentita la presenza di più di un oggetto, se True è consentita.
	 */
	pluginAddHighlighted: function (jsGeometry, bMulti, style) {
	    //Vecchia versione monoblocco 
		if (!bMulti) this.evidenziazioniLayer.destroyFeatures();
		var geoms = new JSGeometryArray();
		
		if(jsGeometry instanceof JSGeometryArray){
			geoms = jsGeometry;
		}else if(jsGeometry instanceof JSGeometry){
			geoms.add(jsGeometry);
		}else{
			alert("tipo sconosciuto " + jsGeometry);
			return;
		}
		
		/*var style_evidenziato = {
	                strokeColor: "#FFCC00",
	                strokeOpacity: 1,
	                strokeWidth: 2,
	                pointRadius: 6,
	                pointerEvents: "visiblePainted",
	                fillColor : "yellow",
	                fillOpacity: 0.7,
	                externalGraphic: "http://localhost:8080/commonintra2-0/img/icone/hand.gif",
	                graphicWidth: 20,
					graphicHeight: 20,
					graphicOpacity: 1,
					graphicXOffset: -10,
					graphicYOffset: -10
	            };*/
		
		var feats = new Array();
		
		for (var i=0; i<geoms.geometries.length; i++) {
			var wkt = new OpenLayers.Format.WKT();
			var feat = wkt.read(geoms.geometries[i].geometry);
			if (style) feat.style = style;
		    feats.push( feat);
		}
		
		this.evidenziazioniLayer.addFeatures(feats);
		//this.map.zoomToExtent(feature.geometry.getBounds());
	},
	
	/**
	 * Method: pluginClearHighlighted
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * bRedraw - {} bRedraw
	 * 
	 * Returns:
	 *     {Boolean}
	 */
	pluginClearHighlighted: function (bRedraw) {
		// non viene gestito bRedraw perche' in questo viewer la cancellazione non richiede il ridisegno
	    this.evidenziazioniLayer.destroyFeatures();
	    // ritorna sempre false perch? il redraw non e' mai necessario
	    return false;
	},

	/**
	 * Method: olGetExtents
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * features - {OpenLayers.Fetures} features
	 * 
	 * Returns:
	 *     {OpenLayers.Bounds}
	 */
	olGetExtents: function(features) {
		var bounds = features[0].geometry.getBounds().clone();
		for(var i=1;i<features.length;i++)
	    	bounds.extend(features[i].geometry.getBounds());
	   	return bounds;
	},

	/**
	 * Method: pluginZoomToHighlighted
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * zoom - {} zoom
	 * buffer - {Number} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	pluginZoomToHighlighted: function (zoom, buffer) {
		//var bounds = this.evidenziazioniLayer.features[0].geometry.getBounds();
		if(!(this.evidenziazioniLayer.features && this.evidenziazioniLayer.features.length>0)) return;
		var bounds = this.olGetExtents(this.evidenziazioniLayer.features);
		if (!zoom) {
			if (buffer && this.isMetresUnits()) {
				var boundsBuffered = new OpenLayers.Bounds();
			    boundsBuffered.extend(new OpenLayers.LonLat(bounds.left-buffer/2,bounds.bottom-buffer/2));
			    boundsBuffered.extend(new OpenLayers.LonLat(bounds.right+buffer/2,bounds.top+buffer/2));
			    this.map.zoomToExtent(boundsBuffered);
			} else {
				this.map.zoomToExtent(bounds);
			}
		} else {
			var lonLat = bounds.getCenterLonLat();
			this.pluginGotoPosition(lonLat.lon, lonLat.lat, zoom, false);	
		}
		
		this.isAlreadyDrawn=true;	
	},

	/**
	 * Method: pluginZoomToExtent
	 * Esegue lo zoom ad uno specifico extent.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * geometry - {Mixed} Stringa wkt della geometria o oggetto di tipo BBox
	 * buffer - {Number} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	pluginZoomToExtent: function (geometry, buffer) {
		
		var bounds;
		
		if (typeof(geometry) == 'string') {
			var wkt     = new OpenLayers.Format.WKT();
			var feature = wkt.read(geometry);
			bounds = feature.geometry.getBounds();
		} else {
			bounds = new OpenLayers.Bounds(geometry.left,geometry.bottom,geometry.right,geometry.top);
		} 
		
		/*
		if (!buffer) {
			this.map.zoomToExtent(bounds);
		} else {
			boundsBuffered = new OpenLayers.Bounds();
		    boundsBuffered.extend(new OpenLayers.LonLat(bounds.left-buffer/2,bounds.bottom-buffer/2));
		    boundsBuffered.extend(new OpenLayers.LonLat(bounds.right+buffer/2,bounds.top+buffer/2));
		    this.map.zoomToExtent(boundsBuffered);
		}
		*/
		
		if (buffer && this.isMetresUnits()) {
			var boundsBuffered = new OpenLayers.Bounds();
		    boundsBuffered.extend(new OpenLayers.LonLat(bounds.left-buffer/2,bounds.bottom-buffer/2));
		    boundsBuffered.extend(new OpenLayers.LonLat(bounds.right+buffer/2,bounds.top+buffer/2));
		    this.map.zoomToExtent(boundsBuffered);
		} else {
			this.map.zoomToExtent(bounds);
		}
	},

	/**
	 * Method: pluginZoomToScale
	 * Esegue lo zoom ad una specifica scala.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * scale - {Number} scale
	 */
	pluginZoomToScale: function (scale) {
		this.map.zoomToScale(scale,true);
	},

	/**
	 * Method: pluginUpdateCustomQuery
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * customQuery - {} customQuery
	 */
	pluginUpdateCustomQuery: function (customQuery ) {
		
		this.customQuery = customQuery;
		
		//TODO Funziona solo con mappa 0
		var nmappa = 0;
		var layAggregCount = this.paramsJS.mapDefinitions[0].getLayerAggregationCount();
		
		for(var index = 0; index < layAggregCount; index++) {
		
			var layViewAggreg = this.paramsJS.mapDefinitions[nmappa].getLayerAggregation(index);
			var bNoTolomeoParams = layViewAggreg.server.noTolomeoParams;
			
			if (!bNoTolomeoParams) {
				var currLayer = this.map.layers[layViewAggreg.nPluginLayer];
			
				var cqBuff = TolomeoExt.ToloViewerOLPanel.customQueryForServer(customQuery[nmappa], layViewAggreg.serverID);
				
				if (currLayer.CLASS_NAME.indexOf("MapServer")!=-1) {
					// in caso di layer mapserver 
					var msParams = TolomeoExt.ToloViewerOLPanel.customQueryToMapserverObj(cqBuff);
					msParams.random= Math.random();
					currLayer.mergeNewParams(msParams);
				} else {
					if (currLayer.CLASS_NAME.indexOf("WMS")!=-1) {
						// in caso di WMS 
						var allParams = TolomeoExt.ToloViewerOLPanel.customQueryToGeoserverObj(cqBuff);
						allParams.random= Math.random();
						// Aggiungo anche parametri secondo standard mapserver per casi WMS servito da mapserver
						var msParams = TolomeoExt.ToloViewerOLPanel.customQueryToMapserverObj(cqBuff);
						Ext.apply(allParams, msParams) 
						currLayer.mergeNewParams(allParams);
					} else {
						// altri cosa fare?	
					}
				}
			}
		}
	},

	
	/**
	 * Method: pluginSetLayerOpacity
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * nomeLayerQuery - {String} nomeLayer
	 * opacity - {float} opacity
	 */
	pluginSetLayerOpacity: function (nPluginLayer, opacity) {
		 this.map.layers[nPluginLayer].setOpacity(opacity);
		/*
		 var param = new Object();
		param["map.layer["+nomeLayer+"]"] = "opacity "+opacity;
		
		this.map.baseLayer.mergeNewParams(param);
		*/
	},

	/**
	 * @method pluginSetLayerEnhance
	 * Modifica i parametri di miglioramento immagine come brightness, contrast etc.
	 *
	 * @params effect {Object} 
	 *
	 */
	pluginSetLayerEnhance: function (effect, nPluginLayer, newValue) {
		var layer = this.map.layers[nPluginLayer];
		this._setLayerEffect(effect, layer, newValue);
		
	},
	
	
    /**
     * 
     * @method _setLayerEffect
     * applica un effetto css (derivato da metodo setOpacity di openlayers)
     * @private
     *
     * @param effect
     * @param layer
     * @param newValue
     */
    _setLayerEffect: function(effect, layer, newValue) {
        
    	var reStr = effect.cssProp + " *\\([^\\)]*\\)";
    	var re = new RegExp(reStr, "i");
    	
    	
    	element=layer.div;
        
        var effectcssval = "";
        if (newValue!=null && newValue != undefined) {
        	effectcssval = effect.cssProp + '(' + newValue + effect.cssUm + ')';
        } else {
        	effectcssval = effect.cssProp + '(' + effect.defaultValue + effect.cssUm + ')';
        }
        if (re.test(element.style['filter'])) {
        	element.style['filter'] =  element.style['filter'].replace(re, effectcssval)  ;
        } else {
        	element.style['filter'] += " "  + effectcssval  ;
        }
        if (re.test(element.style['-webkit-filter'])) {
        	element.style['-webkit-filter'] =  element.style['-webkit-filter'].replace(re, effectcssval)  ;
        } else {
        	element.style['-webkit-filter'] += " "  + effectcssval  ;
        }
  
    },
		
	/**
	 * Method: pluginAddMarker
	 * Permette di aggiungere un marker. Attualmente gestisce un solo marker, quindi quando ne viene aggiunto uno nuovo viene cancellato il precedente.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * x - {float} x
	 * y - {float} y
	 * isUnique - {boolean} Se impostato a true vengono rimossi gli altri markers prima di aggiungere questo
	 */
	pluginAddMarker: function (x, y, iconPath, isUnique) {
		if(isUnique){
			markersLayer.clearMarkers();
		}
		var size = new OpenLayers.Size(20,34);
	    var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
	    var icon = new OpenLayers.Icon(iconPath ? iconPath : this.TOLOMEOServer+ this.TOLOMEOStaticRoot+'img/markers/red_PMarker.png',size,offset);
	    markersLayer.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(x,y),icon));
	},
	
	/**
	 * Method: pluginAddPopup
	 * Permette di aggiungere un popup con pulsante di chiusura.
	 *
	 * Parameters:
	 * x - {float} x
	 * y - {float} y
	 * htmlText - {String} testo del popup in formato html
	 * isUnique - {boolean} se true rimuove tutti gli altri popup presenti
	 * editable - {boolean} se true il popup è cliccabile/editabile
	 * 
	 */
	pluginAddPopup: function (x, y, htmlText, isUnique, editable) {		
		
		var me = this;
		var p = new OpenLayers.Popup.FramedCloud(
                        "popup" + Ext.id(), 
                        new OpenLayers.LonLat(x,y),
                        null,
                        htmlText,
                        null,
                        true,
                        this._onPopupClose
                    );
		p.editable = !!editable;	
        p.closed = false;        
        
        // if editable we have to mange click on contentDiv to edit
        if(p.editable){
        	p.contentDivEvents = new OpenLayers.Events(this, p.contentDiv, null, true);
			p.contentDiv.title = ToloI18n.getMsg("ToloViewerOLPanel.pluginAddPopup.title");
	        function onClick(evt) {
	            me._onPopupUpdate(this);
	            OpenLayers.Event.stop(evt, true);
	        }
	        
	        p.contentDivEvents.on({
	            "click": onClick,
	            scope: p
	        });
	        
	        OpenLayers.Element.addClass(p.contentDiv,'editableNote');        
        }
        
		this.map.addPopup(p, isUnique);	    
		return p;
	},
	
	/**
	 * Method: pluginUpdatePopup
	 * Permatte di modifica il testo di un popup per mezzo del suo id e del nuovo testo
	 *
	 * Parameters:
	 * idPopup - {String} identificativo del popup
	 * htmlText - {String} testo del popup in formato html
	 */
	pluginUpdatePopup: function (idPopup, htmlText) {		
		for(var i in this.map.popups){
			var popup = this.map.popups[i];
			if(popup.id == idPopup){
				popup.setContentHTML(htmlText);
			}
		}   
	},
	
	_onPopupClose: function(e) {
		
		var popup = this;

		// If editable we have to clean event management
		if(popup.editable){
			popup.contentDivEvents.destroy();
        	popup.contentDivEvents = null;
		}
		
		popup.destroy();
		return true;
	},
	
	_onPopupUpdate: function(popup) {
		this.fireEvent("popupClicked",popup.id,popup.contentHTML,popup.lonlat.lon,popup.lonlat.lat);
	},
	
	pluginGetOpenedPopups: function() {
		return this.map.popups;
	},
	
	/**
	 * Method: pluginClearMarkers
	 * Permette di eliminare i marker.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 */
	pluginClearMarkers: function () {
		markersLayer.clearMarkers();
	},

	/**
	 * Method: pluginAutoIdentifyEnable
	 * Permette di aggiungere un marker. Attualmente gestisce un solo marker, quindi quando ne viene aggiunto uno nuovo viene cancellato il precedente.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * bEnable - {Boolean} bEnable
	 */
	pluginAutoIdentifyEnable: function (bEnable) {
		if (bEnable) {
			this.mapControls['autoIdentify'].activate();
		} else {
			this.mapControls['autoIdentify'].deactivate();
		}
	},
	
	/**
	 * Method: pluginAddAutoidentified
	 * Funzione che viene chiamata per aggiungere un oggetto geometrico a quelli selezionati.
	 * Per adesso solo un oggetto e' selezionabile, quindi cancella eventuali oggetto selezionati in precedenza.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer.
	 *
	 * Parameters:
	 * jsGeometry - {JSGeometryArray o JSGeometry} jsGeometry
	 */
	pluginAddAutoidentified: function (jsGeometry) {
		var wkt = new OpenLayers.Format.WKT();
		
		for (var i=0; i<jsGeometry.geometries.length; i++) {
			var feature = wkt.read(jsGeometry.geometries[i].geometry);
			autoIdentifiedLayer.addFeatures([feature]);
		}
	},

	/**
	 * Method: pluginClearAutoidentified
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * bRedraw - {Boolean} bRedraw
	 */
	pluginClearAutoidentified: function (bRedraw) {
		// non viene gestito bRedraw perche' in questo viewer la cancellazione non richiede il ridisegno
	    autoIdentifiedLayer.destroyFeatures();
	    // ritorna sempre false perch? il redraw non e' mai necessario
	    return false;
	},

	/**
	 * Method: pluginZoomToAutoidentified
	 * Esegue lo zoom to selected.
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * zoom - {Number} zoom
	 */
	pluginZoomToAutoidentified: function (zoom) {
		if (autoIdentifiedLayer.features.length==1) {
			var bounds = autoIdentifiedLayer.features[0].geometry.getBounds();
			if (!zoom) {
				this.map.zoomToExtent(bounds);
			} else {
				var lonLat = bounds.getCenterLonLat();
				this.pluginGotoPosition(lonLat.lon, lonLat.lat, zoom, false);	
			}
			
			this.isAlreadyDrawn=true;
		}
	},
		
	/**
	 * Method: pluginPan
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * direction - {} direction
	 * slideFactor - {} slideFactor
	 */
    pluginPan: function(direction, slideFactor){
		 slideFactor = slideFactor || 50;
		 switch (direction) {
            case "N": 
                this.map.pan(0, -slideFactor);
                break;
            case "S": 
                this.map.pan(0, slideFactor);
                break;
            case "O": 
                this.map.pan(-slideFactor, 0);
                break;
            case "E": 
                this.map.pan(slideFactor, 0);
                break;
        }
	},
	
	pluginHistoryPrev: function(){
		if (this.mapControls.navhistory) {
			this.mapControls.navhistory.previous.trigger();
		}
	},
	
	pluginHistoryNext: function(){
		if (this.mapControls.navhistory) {
			this.mapControls.navhistory.next.trigger();
		}
	},
	
	/**
	 * Method: pluginSnapClear
	 * Disattiva tutti i controlli di snap e rende invisibili i relativi layers
	 */
	pluginSnapClear: function(){
		for(var codTPN in this.snapControls){			
			this.pluginSnapDeactivate(codTPN);			
		}		
	},
	
	/**
	 * Method: pluginSnapActivate
	 * Attiva il controllo di snap per il layer relativo al codTPN passato e visualizza tutti i layer
	 * per i quali è possibile fare lo snap.
	 *
	 * Parameters:
	 * codTPN - {int} codice del layer su cui attivare lo snap 
	 */
	pluginSnapActivate: function(codTPN){
		if(this.snapControls[codTPN]){
			for(var l = 0; l < this.snapControls[codTPN][0].layerList.length; l++){
				this.snapControls[codTPN][0].layerList[l].setVisibility(true);
			}
			for(var sc = 0; sc < this.snapControls[codTPN].length; sc++){
				this.snapControls[codTPN][sc].activate();
			}
		}
	},
	
	/**
	 * Method: pluginSnapDeactivate
	 * Disattiva il controllo di snap per il layer relativo al codTPN passato e rende invisibili tutti i layer
	 * per i quali è possibile fare lo snap.
	 *
	 * Parameters:
	 * codTPN - {int} codice del layer su cui disattivare lo snap 
	 */
	pluginSnapDeactivate: function(codTPN){
		if(this.snapControls[codTPN]){
			//if(this.snapControls[codTPN].deactivate){
				for(var sc = 0; sc < this.snapControls[codTPN].length; sc++){
					if(this.snapControls[codTPN][sc] && this.snapControls[codTPN][sc].deactivate){
						this.snapControls[codTPN][sc].deactivate();
						for(var l = 0; l < this.snapControls[codTPN][sc].layerList.length; l++){
							this.snapControls[codTPN][sc].layerList[l].setVisibility(false);
						}
					}
				}
			//}
		}
	},
	
	pluginRemoveAllLayers: function() {
		 var num = this.layersMappa.length;
		 for (var j=0; j<num; j++) {
			 this.map.removeLayer( this.layersMappa[j], false );
		  }  
		 this.layersMappa.length=0;
	},
	
	/**
	 * Method: isBusy
	 * Funzione di busy.
	 *
	 * Parameters:
	 * scale - {Number} scale
	 */
	isBusy: function (){ return this.mapBusy != 0;},
	
	/**
	 * Method: onBusy
	 * Funzione di busy.
	 *
	 * Parameters:
	 * areYouBusy - {Boolean} areYouBusy
	 */
	onBusy: function (areYouBusy){
			if(areYouBusy){
				this.mapBusy++;
				this.refreshBusy();
			}else{
				if (this.mapBusy>0) this.mapBusy--;
				if(!this.isBusy()){
					this.refreshBusy();;
				}
			}
		},
		
	/**
	 * Method: noneBusy
	 * Funzione di busy.
	 * 
	 */	
	noneBusy: function (){
		this.mapBusy = 0;
		if (this.myMask) this.myMask.hide();
	},

	/**
	 * Method: refreshBusy
	 * Funzione di busy
	 */
	refreshBusy: function() {
		if (this.myMask) 
			if (this.mapBusy) this.myMask.show();
			else this.myMask.hide();
	},

	
	/**
	 * Method: relayContainerMove
	 *
	 * Parameters:
	 * ctl - {} ctlBusy

		relayContainerMove: function (ctl) {
			var a= null;
			if(ctl.ownerCt) {
				a= this.relayContainerMove(ctl.ownerCt);
				if (!a) return ctl.ownerCt;
				else return a;
			}
		},*/
	
	getGoogleApiVersion: function() {
		
		return (typeof GMap2 === "function" ? "2" : "3");
		
	},
	
	/** TODO Per adesso non è supportato il meccanismo del caricamento on demand
	 * 
	 */
	loadLayerPrereq: function(tipoLayer, callbackFn) {
		/* TODO
		var urls = this.layerTypePrereq[tipoLayer];
		var url="";
		
		// ALE Da fare scelta per adesso carica la 3
		if (tipoLayer>0 && tipoLayer<5) { // Layer Google
		//	url = (getGoogleApiVersion==2) ? urls[0] : urls[1]; 
			url = urls[1];
		} else {
			url = urls[0];
		}
		if (url!="") loadScript(url, function() { 
										//alert('ciao'); 
										callbackFn(tipoLayer);
										} );
		else callbackFn(tipoLayer);
		*/
	},

	pluginAddAllMaps: function() {
		// Cerca tra le mappe in this.paramsJS.mappe
		for (var i = 0; i<this.paramsJS.mappe.mappaList.length; i++) {
			var mappa = this.paramsJS.mappe.mappaList[i];
			this.pluginAddLayer(mappa, i, this.customQuery, this.map.getNumLayers(), false);
		}
	},
	
	/**
	 * Aggiunge un layer in mappa. Non è supportato l'inserimento di una mappa di un tipo per il quale non sia già stata inclusa l'api se necessaria  
	 * (per esempio una mappa google se non è stato già incluso l'apposito javascript <br/>
	 * Esempio di utilizzo: <br/>
	   <pre>
	  		var mappa = new Object();
			mappa.mapOptions = "layers: 'WMS_PRATO'";
			mappa.overlay = false;
			mappa.SRID = "EPSG:3003";
			mappa.units = "m";
			mappa.mostraInLegenda=true;
			mappa.viewerOptions = "";
			mappa.typeCode = 11;		// WMS
			mappa.nome = "WMS Prato";
			mappa.url = "http://geoserver.comune.prato.it/geoserver/wms";
			tolomeoPnl.api.addLayer(mappa);
	   </pre>
	 * 
	 * @param {} mappa - Oggetto javascript corrispondente alla serializzazione di un tag mappa del file di preset
	 * @param {} nMappa - posizione nel layer switcher
	 * @param {} customQuery - come analogo parametro in olViewerNewLayer
	 */
	pluginAddLayer: function(mappa, nMappa, customQuery, showLayerSwitcher) {
		var me = this;
		//this.loadLayerPrereq(mappa.typeCode,
		//			function() { 
						me.loadLayerCallback(mappa, nMappa, customQuery, showLayerSwitcher) //}
		//			);
		
	},
	
	loadLayerCallback: function(mappa, nMappa, customQuery, showLayerSwitcher) {
		var layer = this.olViewerNewLayer(mappa, nMappa, customQuery);
		  
		if (layer instanceof Array) {
			for (var i=0; i<layer.length; i++) {
				var pos = (layer[i].toloViewerLayerIndex!=undefined && layer[i].toloViewerLayerIndex!=null) ? layer[i].toloViewerLayerIndex : null;
				this._addLayerInMap(layer[i], nMappa, pos, showLayerSwitcher);	
			}
		} else {
			var pos = (layer.toloViewerLayerIndex) ? layer.toloViewerLayerIndex : null;
			this._addLayerInMap(layer, nMappa, pos, showLayerSwitcher);
		}
	},
	
	_addLayerInMap: function(layer, nMappa, pos, showLayerSwitcher) {
		this.layersMappa.push(layer);
		this.map.addLayer(layer);
		if (pos!=undefined && pos!=null) {
			this.map.setLayerIndex(layer, pos);
		}
		var controlId = 'layerSwitcher';
		if ((showLayerSwitcher==undefined || showLayerSwitcher==null || showLayerSwitcher==true) && this.map.getNumLayers()>1 && !this.map.getControl(controlId)) {
			var control = new OpenLayers.Control.LayerSwitcher({activeColor: "#004000", ascending: false});
			control.id = controlId;
			this.map.addControl(control);
		}
		// Se layer.singleTile è definito ed è true
		this.olRegisterLoadEvents(layer);
		if (layer.toloViewerWithBusy) 	this.olRegisterBusyEvents(layer);		
	},
	
	olViewerNewLayer: function (mappa, nMappa, customQuery, positionBase) {
	
		if (positionBase==undefined || positionBase==null) positionBase=0;
		var retVal = [];
		for (var i=0; i<this.paramsJS.mapDefinitions[nMappa].getLayerAggregationCount(); i++) {
			this.paramsJS.mapDefinitions[nMappa].getLayerAggregation(i).nPluginLayer = positionBase+i;
			retVal.push(this.olViewerNewLayer1(nMappa,i, customQuery));
			//retVal.push(this.olViewerNewLayer1(this.paramsJS.mapDefinitions[nMappa].getLayerAggregation(i), customQuery));	
		}
		// inverto l'ordine per sequire la convenzione GIS (layer più in alto visibile sopra gli altri) che e' contraria a quella di openlayers
		return retVal;
	},
	
	//  mappa, nMappa,
	// server, serverOpts, layers, layerOpts
	olViewerNewLayer1: function (nMappa, layerAggregIndex, customQuery) {
		
		// mpOpt mappa.mapOptions --> server opt, parametri che vengono trasmessi al server in query string -> serverOpts
		// viewerOptions --> opzioni del layer openlayers
		
		// layers deve contenere 
		//	nomi layer
		//  stili layer
		
		//TODO LayerSfondo non sono più gestiti qua. li deve gestire il chiamante
	
		var layViewAggreg = this.paramsJS.mapDefinitions[nMappa].getLayerAggregation(layerAggregIndex);
		var server = layViewAggreg.server;
		
		var layersAggreg = layViewAggreg.layers;
		var layerSep;
		
		var layer = null;
		var layerOptions = null;
		//transparent: true
		var mpOpt = { 
				transparent: true,
				wmscalluuid: this.wmscalluuid
		};
		if (this.withWmsCallUUID) {
			mpOpt.wmscalluuid = this.wmscalluuid;
			
		}
		if (server.serverOpts!=null) {
			var buff =Ext.JSON.decode("{" +  server.serverOpts + "}"); // Ext.util.JSON.decode("{" + mappa.mapOptions + "}");
			OpenLayers.Util.extend(mpOpt, buff);
		}

		layerOptions = new Object();
		
		layerOptions.singleTile             = !layViewAggreg.tilesMultiple;
		layerOptions.isBaseLayer            = !layViewAggreg.overlay;
		layerOptions.projection             = layViewAggreg.SRID;
		layerOptions.units                  = layViewAggreg.units;
		layerOptions.displayInLayerSwitcher = layViewAggreg.mostraInLegenda;				
		layerOptions.opacity                = (layViewAggreg['opacity']!=undefined && layViewAggreg['opacity']!=null) ? layViewAggreg['opacity'] : 1;
		
		//layerOptions.transitionEffect       = 'resize';
		
		//ALE aggiunte per layer google che non sentiva quelli dell'oggetto mappa 
		layerOptions.maxExtent = new OpenLayers.Bounds(this.paramsJS.mappe.maxExtentLeft, this.paramsJS.mappe.maxExtentBottom, this.paramsJS.mappe.maxExtentRight, this.paramsJS.mappe.maxExtentTop);
		layerOptions.minScale = this.paramsJS.mappe.minScale;
		layerOptions.maxScale = this.paramsJS.mappe.maxScale;

		var zs = this.getDefaultZoomLevels();
		if (zs!=null) {
			layerOptions.resolutions = [];
			for(var i = 0; i < zs.length; i++) {
				layerOptions.resolutions.push(OpenLayers.Util.getResolutionFromScale(zs[i], layerOptions.units));
			}
		} 

		
		var layerOptionsDaParamsJS = Ext.JSON.decode("{" + layViewAggreg.layerOptions + "}"); // Ext.util.JSON.decode("{" + mappa.viewerOptions + "}");
		Ext.apply(layerOptions, layerOptionsDaParamsJS);
		
		switch (layViewAggreg.server.typeCode) {
			
			// Mapserver
			case 0:
				layerSep = " ";
								
				var layAndStyle = this.paramsJS.getLayerAggregLayersAndStylesStrings(nMappa, layViewAggreg.nPluginLayer, layerSep, this.pluginGetCurrentZoom());
				mpOpt.layers = layAndStyle.layers;
				
				mpOpt.map_imagetype = (layViewAggreg.imageType!= undefined && layViewAggreg.imageType!=null && layViewAggreg.imageType!="") ? layViewAggreg.imageType : "agga";
				mpOpt.map_resolution = OpenLayers.DOTS_PER_INCH;
				
				layerOptions.attribution = layAndStyle.attribution ;
				
				if (customQuery) {
					var cqBuff = TolomeoExt.ToloViewerOLPanel.customQueryForServer(customQuery[nMappa], layViewAggreg.serverID);
					var msParams = TolomeoExt.ToloViewerOLPanel.customQueryToMapserverObj(cqBuff);
					Ext.apply(mpOpt, msParams);
				}
				
				
				
			 	layer = new OpenLayers.Layer.MapServer(server.nome, server.url, mpOpt, layerOptions);	
	            
	            layer.toloViewerWithBusy = layer.singleTile;

				break;

			// Google Streets
			case 1:	
				layer = new OpenLayers.Layer.Google(server.nome,   layerOptions );
				layer.toloViewerWithBusy = false;
				break;

			// Google Physical
			case 2:
				Ext.apply(layerOptions, {  type: (this.getGoogleApiVersion() == "2") ? G_NORMAL_MAP : google.maps.MapTypeId.TERRAIN });
				layer = new OpenLayers.Layer.Google(server.nome,   layerOptions );
				layer.toloViewerWithBusy = false;
				break;
			
			// Google Satellite
			case 3:
				Ext.apply(layerOptions, {  type: (this.getGoogleApiVersion() == "2") ? G_SATELLITE_MAP : google.maps.MapTypeId.SATELLITE });
				layer = new OpenLayers.Layer.Google(server.nome,   layerOptions );
				layer.toloViewerWithBusy = false;
				break;
			
			// Google Hybrid
			case 4:
				Ext.apply(layerOptions, {  type: (this.getGoogleApiVersion() == "2") ? G_HYBRID_MAP : google.maps.MapTypeId.HYBRID });
				layer = new OpenLayers.Layer.Google(server.nome,   layerOptions );
				layer.toloViewerWithBusy = false;
				break;
			
			// Yahoo Sat
			case 5: 
				Ext.apply(layerOptions, {  type: YAHOO_MAP_SAT });
				layer = new OpenLayers.Layer.Yahoo(server.nome, layerOptions);
				layer.toloViewerWithBusy = false;
				break;
			
			// Yahoo Reg
			case 6:
				Ext.apply(layerOptions, {  type: YAHOO_MAP_REG });
				layer = new OpenLayers.Layer.Yahoo(server.nome, layerOptions);
				layer.toloViewerWithBusy = false;
				break;
			
			// Yahoo Hybrid
			case 7:	
				Ext.apply(layerOptions, {  type: YAHOO_MAP_HYB });
				layer = new OpenLayers.Layer.Yahoo(server.nome, layerOptions);
				layer.toloViewerWithBusy = false;
				break;
			
			// Bing Aerial
			case 8:
				Ext.apply(layerOptions, {  type: VEMapStyle.Aerial });
				layer = new OpenLayers.Layer.VirtualEarth(server.nome,   layerOptions );
				layer.toloViewerWithBusy = false;
				break;

			// Bing Shaded
			case 9:
				Ext.apply(layerOptions, {  type: VEMapStyle.Shaded });
				layer = new OpenLayers.Layer.VirtualEarth(server.nome,   layerOptions );
				layer.toloViewerWithBusy = false;
				break;
			
			// Bing Hybrid
			case 10:
				Ext.apply(layerOptions, {  type: VEMapStyle.Hybrid });
				layer = new OpenLayers.Layer.VirtualEarth(server.nome,   layerOptions );
				layer.toloViewerWithBusy = false;
				break;	
			
			// WMS
			case 11: 	    		
				mpOpt.minZoomLevel = 0;
				layerSep = ",";
				var layAndStyle = this.paramsJS.getLayerAggregLayersAndStylesStrings(nMappa, layViewAggreg.nPluginLayer, layerSep, this.pluginGetCurrentZoom()); 
				mpOpt.layers = layAndStyle.layers;
				mpOpt.styles = layAndStyle.stili;
				
				if (customQuery) {
					var cqBuff = TolomeoExt.ToloViewerOLPanel.customQueryForServer(customQuery[nMappa], layViewAggreg.serverID);
					var wmsParams = TolomeoExt.ToloViewerOLPanel.customQueryToGeoserverObj(cqBuff);
					Ext.apply(mpOpt, wmsParams);
					// Aggiungo anche parametri secondo standard mapserver per casi WMS servito da mapserver
					var msParams = TolomeoExt.ToloViewerOLPanel.customQueryToMapserverObj(cqBuff);
					Ext.apply(mpOpt, msParams);
				}
				
				// WMS 1.3.0 vuole CRS, versioni precedenti vogliono CRS. 
				// Aggiungo anche CRS per avere qualcosa che funzioni in entrambi i casi, per non dover prima fare la getcapabilities per stabilire la versione
				mpOpt.CRS = this.pluginGetProjectionCode();
				if (mpOpt.layers == undefined || mpOpt.layers==null || mpOpt.layers=="") {
					layerOptions.visibility=false;
				}				
				if (layViewAggreg.tilesMultiple) {
					mpOpt.tilesorigin = [this.paramsJS.mappe.maxExtentLeft, this.paramsJS.mappe.maxExtentBottom];
					mpOpt.tiled = true;
				}
				
				layerOptions.attribution = layAndStyle.attribution ;
    		    layer = new OpenLayers.Layer.WMS(server.nome, server.url, mpOpt, layerOptions);
    		    layer.id = Math.random();
    		    //layer.id = "OpenLayers.Layer.WMS_" + server.url + mpOpt.layers+Math.random();
    		    layer.toloViewerWithBusy = layer.singleTile;


    		    break;
			
			// OpenStreetMap
			case 12:
				layer = new OpenLayers.Layer.OSM(server.nome);
				layer.toloViewerWithBusy = layer.singleTile;
				break;
				
			default:
				break;
		}
		layer.events.register('moveend', this, this.olLayerMove);
		layer.toloViewerLayerIndex=layViewAggreg.nPluginLayer;
		layer.toloNMappa = nMappa;
		layer.toloLayerSep = layerSep;
		
		// Applica effetti miglioramento immagine
		if(Modernizr.cssfilters){
			for (var i=0; i<ToloParamsJS.enhanceEffects.length; i++ ){
				var effect = ToloParamsJS.enhanceEffects[i];
				var newValue = (layViewAggreg[effect.key]!=undefined && layViewAggreg[effect.key]!=null) ? layViewAggreg[effect.key] : effect.defaultValue;
				this._setLayerEffect(effect, layer, newValue);
			}
		}
		
		//layer.events.register('loadstart', this, function(object, element) { return this.aaaa(object, element,layer, layerSep);});
		
		// TODO ??? layer.numeroMappa = nMappa;
		return layer;
	},

	olLayerScaleFilter: function(object, element) {
		
		for (var i=0; i<this.layersMappa.length; i++) {
			var layer=this.layersMappa[i];
					
			var layAndStyle = this.paramsJS.getLayerAggregLayersAndStylesStrings(layer.toloNMappa, layer.toloViewerLayerIndex, layer.toloLayerSep, ((object && object.zoomChanged && object.zoom && this.map.baseLayer) ? OpenLayers.Util.getScaleFromResolution(this.map.getResolutionForZoom(object.zoom), this.map.baseLayer.units) : this.pluginGetCurrentZoom()));
			
			if (layAndStyle.layers=="") {
				layer.setVisibility(false);
			} else {
				
				// modifica con i nuovi parametri
				//layer.mergeNewParams({layers: layAndStyle.layers, styles:  layAndStyle.stili });
				// Non utilizzo la mergeNewParams perchè innesca un redraw. Modifico layer.params direttamente (funzione non documentata, visto dai sorgenti il funzionamento della mergeNewParams)							
				if(layer.CLASS_NAME.indexOf("WMS")!=-1){
					// Aggiunto controllo su WMS, perchè altrimenti per Mapserver vengono inviati due parametri: "layer" e "LAYER" ed il secondo sovrascrive il primo non facendo 
					// correttamente i soli layers che devono essere accesi e/o spenti									
					layer.params = OpenLayers.Util.extend(layer.params, {LAYERS: layAndStyle.layers, STYLES:  layAndStyle.stili });					
				} else {
					layer.params = OpenLayers.Util.extend(layer.params, {layers: layAndStyle.layers, styles:  layAndStyle.stili });
				}
				
				layer.setVisibility(true);
			}
		}
		return true;
	},
	
	olLayerMove: function(obj) {
		//if (obj.zoomChanged)
		this.fireEvent("onMapMoveEnd", obj);
		
	},
	
	/**
	 * Method: olAutoIdentifyOnPause
	 *
	 * Parameters:
	 * e - {} evento.
	 */
	olAutoIdentifyOnPause: function (e){
		var lonlat = this.map.getLonLatFromViewPortPx(e.xy);
		this.fireEvent('onAutoIdentify', new Point(lonlat.lon, lonlat.lat), e.clientX, e.clientY, e.xy.x, e.xy.y);
		//onAutoIdentify(new Point(lonlat.lon, lonlat.lat), e.clientX, e.clientY);
	},
		
	/**
	 * Method: olAutoIdentifyOnMove
	 *
	 */
	olAutoIdentifyOnMove: function olAutoIdentifyOnMove() {
		this.fireEvent('onAutoIdentifyCancel', null);
		//onAutoIdentifyCancel();
	},
	
	/**
	 * Method: olHandleMeasurements
	 *
	 * Parameters:
	 * e - {} event
	 * partial - Boolean tha specify if measure is partial or final
	 *
	 * Returns:
	 *     {Booelan} 
	 */
	olHandleMeasurements : function (event,partial) {
		
		var control = event.control;
        var geometry = event.geometry;
        var units = event.units;
        var order = event.order;
        var measure = event.measure;            
        var returnObj = {dimension: order};        
                    
        if(order == 1) {
        	
            returnObj.length = {
            	'units' : units,
            	'measure' : measure
            }            
            returnObj.area = {            
            	'units' : units,
            	'measure' : 0
            }
            
        } else {
        	
        	var length = control.getBestLength(geometry);
        	
        	returnObj.length = {
            	'units' : length[1],
            	'measure' : length[0]
            }            
            returnObj.area = {            
            	'units' : units,
            	'measure' : measure
            }                       
        }            
        
        if(partial){
        	this.fireEvent('onMeasureChanging', returnObj);
        } else {
        	this.fireEvent('onMeasureChanged', returnObj);
        }
    },

	/**
	 * Method: olRegisterBusyEvents
	 *
	 * Parameters:
	 * layer - {} layer.
	 *
	 * Returns:
	 *     {Booelan} 
	 */
	olRegisterBusyEvents: function (layer) {
			layer.events.register("loadstart",  this, function () { this.onBusy(true); } );
			layer.events.register("loadend",    this, function () { this.onBusy(false);} );
			layer.events.register("loadcancel", this, function () { this.onBusy(false);} );
			
			return true;
	},

	olRegisterLoadEvents: function (layer) {
		layer.events.register("loadstart",  this, function () { this.fireEvent('loadstart'); } );
		layer.events.register("loadend",    this, function () { this.fireEvent('loadend');  } );
		layer.events.register("loadcancel", this, function () { this.fireEvent('loadcancel'); } );
		
		return true;
	},
	
	
	/**
	 * Method: activateControl
	 * Attiva un controllo disattivando tutti gli altri. Agisce su tutti i controlli con esclusione di quelli relativi al drawlayer (vedi activateControlDrawLayer)
	 *
	 * Parameters:
	 * nome - {String} nome.
	 */
	activateControl: function (nome) {
	    for (var key in this.mapControls) {
	    	if ( (key!='legend') && (key!=nome)  && (key!='navigation') && (key!='navhistory')) { 
	    		// lancio timeout invece di fare direttamente perche' viene invocato all'interno di un evento e si verificava errore this.point has no properties
	        	//setTimeout( "this.mapControls['"+key+"'].deactivate()", 2500 );
	        	this.mapControls[key].deactivate();	        	
	    	}
	    }
	    
	    this.mapControls[nome].activate();	    
	},
	
	/**
	 * Method: activateControl
	 * Attiva un controllo disattivando tutti gli altri. Agisce esclusivamente sui controlli relativi al drawlayer (vedi anche activateControl)
	 *
	 * Parameters:
	 * nome - {String} nome.
	 */
	activateControlDrawLayer: function (nome) {
	    for (var key in this.mapControlsDrawLayer) {
	        	this.deactivateControlDrawLayer(key);
	    }
	    this.mapControlsDrawLayer[nome].activate();
	},

	
	/**
	 * Method: deactivateControl
	 * Disattiva un controllo.
	 *
	 * Parameters:
	 * nome - {String} nome
	 */
	deactivateControl: function (nome) {
		this.mapControls[nome].deactivate();
	},
	
	/**
	 * Method: deactivateControlDrawLayer
	 * Disattiva un controllo.
	 *
	 * Parameters:
	 * nome - {String} nome
	 */
	deactivateControlDrawLayer: function (nome) {
		this.mapControlsDrawLayer[nome].deactivate();
	},
	
	/**
	 * Method: olViewerGeometryToGeometry
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 *
	 * Returns:
	 *     {JSGeometryArray o JSGeometry} 
	 */
	olViewerGeometryToGeometry: function (geom) {
	    var jsGeometry = new JSGeometry();
	    
	    var wkt = new OpenLayers.Format.WKT();

	    if (geom.geometry == undefined) {
	    	jsGeometry.geometry = wkt.write(geom.feature);
	    } else { 
	    	jsGeometry.geometry = wkt.write(geom);
	    }
	    jsGeometry.SRID = this.paramsJS.mappe.SRID;
		
	    if (jsGeometry.geometry.indexOf("POINT")!=-1){
	    	jsGeometry.geometryIsValid = true;
	    } else {
	    	if (jsGeometry.geometry.indexOf("LINE")!=-1){
	    		var v = geom.feature.geometry.getVertices();
		    	if (v.length>2 || 
		    		(v.length==2 && (v[0].x!=v[1].x || v[0].y!=v[1].y))){
		    			jsGeometry.geometryIsValid = true;		
		    	} else {
		    		jsGeometry.geometryIsValid = false;
		    	}
		    } else {
		    	if (jsGeometry.geometry.indexOf("POLYGON")!=-1){
		    		var v = geom.feature.geometry.getVertices();
			    	if (v.length>3 || 
			    		(v.length==3 && (
			    				(v[0].x!=v[1].x || v[0].y!=v[1].y) &&
			    				(v[0].x!=v[2].x || v[0].y!=v[2].y) &&
			    				(v[1].x!=v[2].x || v[1].y!=v[2].y)))){
			    			jsGeometry.geometryIsValid = true;		
			    	} else {
			    		jsGeometry.geometryIsValid = false;
			    	}	
			    }		
		    }	
	    }
	    
		return jsGeometry;
	},

	/**
	 * Method: olViewerOnDigitizedPoint
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 * 
	 */
	olViewerOnDigitizedPoint: function (geom) {
		// Chiama la funzione di TolomeoIF
		this.fireEvent('onDigitizeEndPoint', this.olViewerGeometryToGeometry(geom));
		//onDigitizeEndPoint(this.olViewerGeometryToGeometry(geom));
		this.activateControl('navigation');
	},
	
	/**
	 * Method: olViewerOnDigitizedPointFromRef
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 * 
	 */
	olViewerOnDigitizedPointFromRef: function (geom) {
		// Chiama la funzione di TolomeoIF
		this.fireEvent('onDigitizePointFromRefEnd', this.olViewerGeometryToGeometry(geom));
		this.olViewerOnDigitizedPoint(geom);
	},
	
	/**
	 * Method: olViewerOnDigitizedPointByCAD
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 */
	olViewerOnDigitizedPointByCAD: function (geom) {
		// Chiama la funzione di TolomeoIF
		this.fireEvent('onDigitizePointByCADEnd', this.olViewerGeometryToGeometry(geom));
		this.olViewerOnDigitizedPoint(geom);
		
	},
	
	/**
	 * Method: olViewerOnDigitizedLine
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 */
	olViewerOnDigitizedLine: function (geom) {
		this.fireEvent('onDigitizeEndLine', this.olViewerGeometryToGeometry(geom));
		this.activateControl('navigation');
	},
	
	/**
	 * Method: olViewerOnDigitizedLineByCAD
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 */
	olViewerOnDigitizedLineByCAD: function (geom) {
		// Chiama la funzione di TolomeoIF
		this.fireEvent('onDigitizeLineByCADEnd', this.olViewerGeometryToGeometry(geom));
		this.olViewerOnDigitizedLine(geom);
		
	},
	
	/**
	 * Method: olViewerOnDigitizedPolygon
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 * 
	 */
	olViewerOnDigitizedPolygon: function (geom) {
		// Chiama la funzione di TolomeoIF
		this.fireEvent('onDigitizeEndPolygon', this.olViewerGeometryToGeometry(geom));
		//onDigitizeEndPolygon(this.olViewerGeometryToGeometry(geom));
		this.activateControl('navigation');
	},
	
	/**
	 * Method: olViewerOnDigitizedPolygonByCAD
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 * 
	 */
	olViewerOnDigitizedPolygonByCAD: function (geom) {
		// Chiama la funzione di TolomeoIF
		this.fireEvent('onDigitizePolygonByCADEnd', this.olViewerGeometryToGeometry(geom));		
		this.olViewerOnDigitizedPolygon(geom);
	},

	/**
	 * Method: olViewerOnVertexEditingEnd
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 */
	olViewerOnVertexEditingEnd: function (geom) {
		this.fireEvent('onDigitizeEndVertexEditing', this.olViewerGeometryToGeometry(geom));
		this.activateControl('navigation');
	},
	
	
	/**
	 * Method: olViewerOnDigitizedFeatureVertexEditingEnd
	 * Funzione chiamata alla fine di una azione di vertex editing su una feature già digitalizzata in precedenza
	 * Parameters:
	 * geom - {} la geometria.
	 */
	olViewerOnDigitizedFeatureVertexEditingEnd: function (geom) {
		this.fireEvent('onDigitizedFeatureVertexEditingEnd', this.olViewerGeometryToGeometry(geom));
	},
		
	/**
	 * Method: olViewerOnDragDropEnd
	 *
	 * Parameters:
	 * geom - {} la geometria.
	 */
	olViewerOnDragDropEnd: function (geom) {
		this.fireEvent('onDigitizeEndDragDrop', this.olViewerGeometryToGeometry(geom));
		this.activateControl('navigation');
	},
	
	/**
	 * Method: olViewerOnDigitizedFeatureDragDropEnd
	 * Funzione chiamata alla fine di una azione di drag and drop su una feature già digitalizzata in precedenza
	 * Parameters:
	 * geom - {} la geometria.
	 */
	olViewerOnDigitizedFeatureDragDropEnd: function (geom) {
		this.fireEvent('onDigitizedFeatureDragDropEnd', this.olViewerGeometryToGeometry(geom));
	},
	
	/**
	 * Method: pluginSetDistanceFromRef
	 * Set the distance from the reference point
	 * 
	 * Prameters:
	 * distance - {} the distance
	 */
	pluginSetDistanceFromRef: function(distance){
		this.mapControlsDrawLayer['pointFromRef'].handler.setDistance(distance);
	},
	
	/**
	 * Method: getDefaultZoomLevels
	 *
	 * Returns:
	 *     Il valore di zoom di default.
	 */
	getDefaultZoomLevels : function(){			
		var defaultZoomLevels = this.paramsJS.mappe.zoomLevels.split(",");
		var zoomLevels = [];
		if(defaultZoomLevels){
			for(var i = 0; i<defaultZoomLevels.length; i++){
				var defaultZoomLevel = parseInt(defaultZoomLevels[i]); 
				if(defaultZoomLevel <= this.paramsJS.mappe.minScale && defaultZoomLevel >= this.paramsJS.mappe.maxScale)
					zoomLevels.push(defaultZoomLevel);
			}
		}			
		
		return zoomLevels;
	},
	
		
	/**
	 * Method: pluginGetCoordinateActivate
	 * Esegue il necessario per attivare la rilevazione delle coordinate
	 */
	/*
	pluginGetCoordinateActivate : function(){
		this.map.events.register("click", this, this.notifyCoordinate);
	},
	*/
	/**
	 * Method: notifyCoordinate
	 * Notifica il cambio/rilevazione di coordinate
	 */
	/*
	notifyCoordinate: function(evt){
		var mousexy = evt.xy;
		var lonlat = this.map.getLonLatFromPixel(mousexy);
		var coords = {x:lonlat.lon,y:lonlat.lat};
		this.fireEvent('onCoordinateChange', mousexy, coords, this.pluginGetProjectionCode());
	},
	*/
	/**
	 * Method: pluginGetCoordinateDeactivate
	 * Esegue il necessario per disattivare la rilevazione delle coordinate
	 */
	/*
	pluginGetCoordinateDeactivate : function(){		
		this.map.events.unregister("click", this, this.notifyCoordinate);
	},
	*/
	
	/**
	 * Method: pluginGetProjectionCode
	 * @return {String} restituisce il codice EPSG del sistema di riferimento
	 */
	pluginGetProjectionCode: function(){
		return this.map.getProjection() || this.map.projection;
	},

	// Gestione Google Streetview
	bindToStreetviewViewer: function(streetviewViewer) {
		if (streetviewViewer) {	
			streetviewViewer.on('onPositionChanged', this.pluginUpdateStreetviewPosition, this);
			streetviewViewer.on('onPovChanged'     , this.pluginUpdateStreetviewPosition, this);
			streetviewViewer.on('onLinksChanged'   , this.pluginStreetviewDrawNavLinks  , this);
		}
	},
	
	
	pluginAddStreetviewLayers: function() {
		
		var me = this;		
		
		// Layer del marker: contenete la posizione relativa alla scena streetview visualizzata e il simbolo utilizzato indica anche la direzione di visualizzazione
		this.streetViewMarkerLayer = new OpenLayers.Layer.Vector("Google Streetview Marker", {
        	styleMap: new OpenLayers.StyleMap({
            	"default": {
                    externalGraphic: this.TOLOMEOServer  + this.TOLOMEOStaticRoot + 'img/streetview/tool.png',
                    graphicHeight: 32,
                    graphicWidth: 32,
                    graphicOpacity: 0.8,
                    rotation: "${yaw}"
                },
                "select": {
                    cursor: "pointer"
                }
            })
		});		
		
        // Layer contenete le freccette che indicano in quale direzione è possibile navigare con streetview
		this.streetViewNavigationLinkLayer = new OpenLayers.Layer.Vector("Google Streetview Navigation Links", {
            styleMap: new OpenLayers.StyleMap({
                "default": {
                    externalGraphic: this.TOLOMEOServer +  this.TOLOMEOStaticRoot + 'img/streetview/link.png',
                    graphicHeight: 24,
                    graphicWidth: 16.5,
                    graphicYOffset: -44,
                    graphicOpacity: 0.8,
                    rotation: "${angle}"
                },
                "temporary": {
                    cursor: "pointer",
                    externalGraphic: this.TOLOMEOServer +  this.TOLOMEOStaticRoot + '/img/streetview/link_selected.png'
                }
            })
        });
		
		this.map.addLayer(this.streetViewMarkerLayer);
		this.map.addLayer(this.streetViewNavigationLinkLayer);

		// Controllo DragFeature per drag drop punto di panorama
        this.streetViewDragControl = new OpenLayers.Control.DragFeature(this.streetViewMarkerLayer, {
            onComplete: function(feature, pixel) {
		    	var position = me.map.getLonLatFromPixel(pixel);
		        var currPoint = new Point(position.lon,position.lat);	
		        // riproietto le coordinate
		        currPoint.transform(me.pluginGetProjectionCode(),"EPSG:4326");        
		        me.fireEvent('onStreetviewDropComplete', currPoint.x ,currPoint.y);
        	}
        });
                      
        
        var streetviewDelegatorWidget = Ext.create('TolomeoExt.ToloViewerOLPanel.SelectFeatureControlManager.DelegatorWidget',{
	    	id : 'streetview',
	    	layers : [this.streetViewNavigationLinkLayer,this.streetViewMarkerLayer],
	    	callbacks: {
		    	onSelect : function(layerName,feature,viewer){
		    		viewer.fireEvent('onStreetviewNavLinkClick', feature.attributes.panoId);
		    	},	    	
		    	onDeactivate : function(viewer) {
		    		viewer.streetViewNavigationLinkLayer.destroyFeatures();
		    		viewer.streetViewMarkerLayer.destroyFeatures();
		    	}
	    	},
	    	moreControls : [this.streetViewDragControl]
	    });
        	
        this.routingControlManager.addDelegator(streetviewDelegatorWidget);

	},
	
	
	/*
	_addSelectFeatureControl: function(layers, options) {
		var allLayers = layers.concat(this.selectFeatureCurrLayers);
		var ctrl =  new OpenLayers.Control.SelectFeature(allLayers, options);
		this.selectFeatureCurrLayers = allLayers;
		
		return ctrl;
	},*/
	/*
	pluginRemoveStreetviewLayers: function() {
		
		this.streetViewDragControl.deactivate();
		this.streetviewSelectControl.deactivate();
		this.streetviewHighlightCtrl.deactivate();
		
		this.map.removeLayer(this.streetViewMarkerLayer);
		this.map.removeControl(this.streetViewDragControl);
		this.map.removeLayer(this.streetViewNavigationLinkLayer);
		this.map.removeControl(this.streetviewSelectControl);
		this.map.removeControl(this.streetviewHighlightCtrl);
	},
	*/
	pluginUpdateStreetviewPosition: function(lon, lat, heading) {
		
			// Destroy the existing features
	        this.streetViewMarkerLayer.destroyFeatures();
	        
	        var currPoint = new Point(lon,lat);			
			// riproietto le coordinate
	        currPoint.transform("EPSG:4326",this.pluginGetProjectionCode());
	        // Compute the new position
	        var pos = new OpenLayers.Geometry.Point(currPoint.x, currPoint.y);
	        
	        // Add a vector feature in navigation layer
	        var panomarker = new OpenLayers.Feature.Vector(pos, {yaw: heading});
	        this.streetViewMarkerLayer.addFeatures([panomarker]);
	        
	        //TODO l'evento linkschanged scatta automaticamente quando cambia posizione? In questo caso questa chiamata è inutile 
	        //this.pluginStreetviewDrawNavLinks();
	   
			// DA FARE
			// controllre anche se pos cambiata per evitare inutili
			
	}, 
	
	pluginStreetviewDrawNavLinks: function(links, position) {
		
        //var links = this.panorama.getLinks();
		//var position = this.panorama.getPosition();
		
		// Destroy the existing features
        this.streetViewNavigationLinkLayer.destroyFeatures();
        // Add new link symbols
        this.navigationLinks = [];
        if (links) {
            for (var i = 0; i < links.length; i++) {
                var link = links[i];
                
                //////////////////////////////////////////////////////////////////
    	        var centerPoint = new Point(position.lng(),position.lat());    			
    			// riproietto le coordinate
    	        centerPoint.transform("EPSG:4326",this.pluginGetProjectionCode());
    	        // Compute the new position
    	        var centerPosition = new OpenLayers.Geometry.Point(centerPoint.x, centerPoint.y);
    	        
    			//////////////////////////////////////////////////////////////////
                
                //TODO chiamare proj4js con funzioni lazy di federico o meglio funzione su api
    	        /*
                var centerPosition = new OpenLayers.Geometry.Point(position.lng(), position.lat());
                centerPosition.transform(new OpenLayers.Projection("EPSG:4326"), this.map.getProjectionObject());
                */
                // Add a vector feature as navigation link
		        this.navigationLinks.push(new OpenLayers.Feature.Vector(centerPosition, {angle: link.heading, panoId: link.pano}));
            }
            if (this.navigationLinks.length > 0) {
      	        this.streetViewNavigationLinkLayer.addFeatures(this.navigationLinks);
            }
        }
    },
    
    pluginGetCoordinateFromPixel: function(pixelxy){
    	var lonlat = this.map.getLonLatFromPixel(pixelxy);
    	return {x:lonlat.lon, y:lonlat.lat};
    },
    
    pluginGetPixelFromCoordinate: function(lonlat){
    	return this.map.getPixelFromLonLat(lonlat);    	
    },
    
    /**
	* Method: pluginRoutingActivate
	* Activate routing controls.
	*/
    pluginRoutingActivate: function() {
    	this.routingControlManager.activateDelegator('routing');    	
    },
    
    /**
	* Method: pluginRoutingDeactivate
	* Deactivate routing controls.
	*/
    pluginRoutingDeactivate: function() {
    	this.routingControlManager.deactivateDelegator('routing');
    },
    
    /**
	* Method: pluginRoutingActivate
	* Deactivate streetview controls.
	*/
    pluginStreetViewActivate: function() {
		this.routingControlManager.activateDelegator('streetview');
	},
	
	/**
	* Method: pluginRoutingDeactivate
	* Deactivate streetview controls.
	*/
    pluginStreetViewDeactivate: function() {
    	this.routingControlManager.deactivateDelegator('streetview');	
	},
	
	
    
	/**
     * Restituisce la larghezza di questo viewer
     */
	pluginGetMapViewerWidth: function() {
    	return this.getWidth();
    	
    },
    
    /**
     * Restituisce l'altezza di questo viewer
     */
    pluginGetMapViewerHeight: function() {
    	return this.getHeight();
    	
    },
    
    /**
     * Restituisce la larghezza dell'oggetto mappa incluso in questo viewer
     */
    pluginGetMapWidth: function() {
    	return this.map.size.w;
    	
    },
    
    /**
     * Restituisce l'altezza dell'oggetto mappa incluso in questo viewer
     */
    pluginGetMapHeight: function() {
    	return this.map.size.h;
    	
    },
    
    pluginGetMapRatio: function() {
    	var ratio = this.map.baseLayer.ratio;
    	return (ratio) ? ratio : 1;
    	
    },

    //getItemUrlFromViewer
    /**
     * Restituisce l'url necessaria per richiedere l'immagine corrispondente alla posizione/zoom attuali ad un server/layer alternativo indicato in itemParams
     *
     * @param itemParams {Object} contiene url, layer, tipo di server ed altri parametri relativi al server per il quale deve essere predisposta l'url
     * @param mapWidth larghezza della mappa da richiedere
     * @param mapHeight altezza della mappa da richiedere
     * 
     *    
     */
    pluginServerUrl: function (itemParams, mapWidth, mapHeight ) {
		var retVal = '';
		
		// Recupero parametri necessari da viewer
	    var fullBounds = this.pluginGetMapFullExtent();
	    var viewerFullUrl = this.pluginGetMapUrl(fullBounds);
	    var mapDPI = this.pluginGetDotsPerInch();
	    
	    if ( itemParams.tipo==undefined || itemParams.tipo==null || itemParams.tipo=='') {
	    	itemParams.tipo = 'mapserver';
	    }
	    
	    switch (itemParams.tipo) {	    
		    case 'mapserver':
		    	// url     ----- http://dvptolomeo.comune.prato.it/cgi-bin/mapserv?   
		    	// mappa   ----- map=/usr1/test/vh/tolomeo/mapfiles/stradario.map
		    	// layer   ----- layers=undefined%20circoscrizioni%20fiumi_laghi%20parchi%20edifici%20poligoni_strade%20piste_ciclabili%20cartelli_stradali%20numeri_civici
		    	// formato -----   map_imagetype=agga
		    	// map_resolution=72
		    	// mode=map 
		    	// fullbounds ----- mapext=1668361.0250593+4860744.3379923+1668543.5334328+4860867.2330781
		    	// fullbounds ----- imgext=1668361.0250593+4860744.3379923+1668543.5334328+4860867.2330781
		    	// ???? map_size=1194+804  // calcolare da this.mapViewerRatio etc?
		    	// ?? punto centrale ?? imgx=597&imgy=402
		    	// ???? imgxy=1194+804
		    	
		    	// url
		    	retVal = (itemParams.url && itemParams.url != "") ? itemParams.url :   
		    															(viewerFullUrl.indexOf('?')!=-1) ? viewerFullUrl.substring(0, viewerFullUrl.indexOf('?')) : viewerFullUrl;
		    	retVal += (retVal.indexOf('?')==-1) ?  "?" : "&";
		    	// mappa
		    	retVal += "map=" + escape(itemParams.mappa) + "&";
		    	// layer
		    	retVal += "layers=" + escape(itemParams.layer) + "&";
		    	//formato
		    	retVal += "map_imagetype=" + ((itemParams.formato && itemParams.formato!="") ? escape(itemParams.formato) : "agga") + "&";
		    	// resolution
		    	retVal += "map_resolution=" + mapDPI + "&";
		    	// mode
		    	retVal += "mode=map&";
		    	// mapext
		    	retVal += "mapext=" + fullBounds.left + "+" + fullBounds.bottom + "+" + fullBounds.right + "+" + fullBounds.top + "&";
		    	// imgext
		    	retVal += "imgext=" + + fullBounds.left + "+" + fullBounds.bottom + "+" + fullBounds.right + "+" + fullBounds.top + "&";
		    	// map_size
		    	retVal += "map_size=" + mapWidth + "+" + mapHeight + "&";
		    	// imgx e imgy
		    	retVal += "imgx=" +  Math.round(mapWidth/2) + "&";
		    	retVal += "imgy=" +  Math.round(mapHeight/2)+ "&";
		    	// imgxy
		    	retVal += "imgxy=" + mapWidth + "+" + mapHeight ;
		    	
		    	break;
		    	
		    case 'WMS':
		    	// http://geoserver.comune.prato.it/geoserver/wms?
		    	// LAYERS=comunepo_generica
		    	// MINZOOMLEVEL=0
		    	// SERVICE=WMS
		    	// VERSION=1.1.1
		    	// REQUEST=GetMap
		    	// STYLES=
		    	// EXCEPTIONS=application%2Fvnd.ogc.se_inimage
		    	// FORMAT=image%2Fjpeg
		    	// SRS=EPSG%3A3003
		    	// BBOX=1630695.3952703,4847788.25,1703123.6047297,4873514.75
		    	// WIDTH=1875
		    	// HEIGHT=666
		    	
		    	// url
		    	retVal = (itemParams.url && itemParams.url != "") ? itemParams.url :   
		    															(viewerFullUrl.indexOf('?')!=-1) ? viewerFullUrl.substring(0, viewerFullUrl.indexOf('?')) : viewerFullUrl;
		    	retVal += (retVal.indexOf('?')==-1) ?  "?" : "&";
		    	// layer
		    	retVal += "LAYERS=" + escape(itemParams.layer) + "&";
		    	//MINZOOMLEVEL
		    	retVal += "MINZOOMLEVEL=0&";
		    	//SERVICE
		    	retVal += "SERVICE=WMS&";
		    	//VERSION
		    	retVal += "VERSION=1.1.1&";
		    	// REQUEST
		    	retVal += "REQUEST=GetMap&";
		    	// STYLES
		    	retVal += "STYLES=" + itemParams.styles + "&";
		    	// EXCEPTIONS
		    	retVal += "EXCEPTIONS=application%2Fvnd.ogc.se_inimage&";
		    	//formato
		    	retVal += "FORMAT=" + ((itemParams.formato && itemParams.formato!="") ? escape(itemParams.formato) : "image%2Fjpeg") + "&";
		    	// SRS
		    	retVal += "SRS=" + ((itemParams.srid && itemParams.srid!="") ? escape(itemParams.srid) : escape(this.pluginGetSRID()))  + "&";
		    	// bbox
		    	retVal += "BBOX=" + fullBounds.left + "," + Math.round(fullBounds.bottom) + "," + fullBounds.right + "," + fullBounds.top + "&";
		    	// WIDTH ed HEIGHT
		    	retVal += "WIDTH=" + mapWidth + "&HEIGHT=" + mapHeight ;
		    	break;	
	    
	    }
		return retVal;
	},
    
	pluginGetObjPos: function () {
    	
    	return {
    		srid:   this.pluginGetSRID(),
    		bbox:   this.pluginGetMapExtent(),
    		width:  this.pluginGetMapWidth(),
    		height: this.pluginGetMapHeight() 
    	}
    	
	}, 
	
	   
	/**
	 * Method: pluginAddRouting
	 * Funzione che viene chiamata per aggiungere un oggetto geometrico a quelli del routing.
	 * Se bMulti non definito o false un solo oggetto e' evidenzxiabile, quindi cancella eventuali oggetto selezionati in precedenza
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicatoad un certo viewer.
	 *
	 * Parameters:
	 * routing - {RouteResponse} reouting da aggiungere
	 * bMulti - {Boolean} bMulti Se non definito o false non è consentita la presenza di più di un oggetto, se True è consentita.
	 */
	pluginAddRouting: function (routing, bMulti, style) {
		
		var jsGeometry = routing.geometry;
		
		if (!bMulti) this.routingLayer.destroyFeatures();
		/* Modificato per non tracciare la feature completa ma i singoli pezzi per rednerli selezionabili
		 
		var geoms = new JSGeometryArray();
		
		if (jsGeometry instanceof JSGeometryArray) {
			geoms = jsGeometry;
		} else if (jsGeometry instanceof JSGeometry) {
			geoms.add(jsGeometry);
		} else {
			alert("tipo sconosciuto " + jsGeometry);
			return;
		}
		
		var feats = new Array();
		
		for (var i=0; i<geoms.geometries.length; i++) {
			var wkt = new OpenLayers.Format.WKT();
			var feat = wkt.read(geoms.geometries[i].geometry);
			if (style) feat.style = style;
		    feats.push( feat);
		}
		//ALE	this.routingLayer.addFeatures(feats);
		*/
		
		for (var i = 0; i < routing.instructions.length; i++) {
			this._routingInstructionAdd(routing.instructions[i].geometry, { tooltip: routing.instructions[i].textInstruction }, i!=0, routing.instructions[i].instructionId);
		}
		
	},
	
	pluginRoutingInstructionHighlight: function (instruction, bHighlight) {
		
		var feats = this.routingLayer.getFeaturesByAttribute("instructionId", instruction.instructionId);
		for (var i=0; i<feats.length; i++) {
			this.routingLayer.drawFeature(feats[i], (bHighlight) ? "highlight" : "default");	
		}

	},
		
	_routingInstructionAdd: function(jsGeometry, opts, withNode, instructionId) {
		var wkt = new OpenLayers.Format.WKT();
		var feat = wkt.read(jsGeometry.geometry);
		feat.attributes.instructionId = instructionId;
		
		// Aggiunta feature lineare
		this.routingLayer.addFeatures([feat]);
		
		if (withNode) {
			var startPoint = feat.geometry.getVertices(true)[0];
			
			var o = opts || {};
			
			TolomeoExt.applyIfEmpty(o, {
				icon	: this.TOLOMEOServer + this.TOLOMEOStaticRoot + 'img/ols/routeInfo.png',
				widht	: 11,
				height	: 11,
				xOffset	: -5,
				yOffset	: -5,
				tooltip	: ToloI18n.getMsg("ToloViewerOLPanel._routingInstructionAdd.tooltip")
			});
			
			var infoFeature = new OpenLayers.Feature.Vector(startPoint, 
					{	instructionId   : instructionId }, 
					{
						externalGraphic	: o.icon,
						graphicWidth	: o.widht,
						graphicHeight	: o.height,
						graphicXOffset	: o.xOffset,
						graphicYOffset	: o.yOffset,
						title			: o.tooltip
					});
			
			// Aggiunta nodo
			this.routingLayer.addFeatures([infoFeature]);	
		}
		
	},
	
	pluginZoomToInstruction: function(jsGeometry, zoomFactor) {
		var wkt = new OpenLayers.Format.WKT();
		var feat = wkt.read(jsGeometry.geometry);
		var startPoint = feat.geometry.getVertices(true)[0];
		
		this.pluginGotoPosition(startPoint.x, startPoint.y, zoomFactor, false);  
	},
	
	/**
	 * Method: pluginClearRouting
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * bRedraw - {} bRedraw
	 * 
	 * Returns:
	 *     {Boolean}
	 */
	pluginClearRouting: function (bRedraw) {
		// non viene gestito bRedraw perche' in questo viewer la cancellazione non richiede il ridisegno
	    this.routingLayer.destroyFeatures();
	    // ritorna sempre false perch? il redraw non e' mai necessario
	    return false;
	},
	
	/**
	 * Method: pluginZoomToRouting
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * zoom - {} zoom
	 * buffer - {Number} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	*/
	pluginZoomToRouting: function (zoom, buffer) {
		//var bounds = this.routingLayer.features[0].geometry.getBounds();
		if(!(this.routingLayer.features && this.routingLayer.features.length>0)) return;
		var bounds = this.olGetExtents(this.routingLayer.features);
		if (!zoom) {
			if (buffer && this.isMetresUnits()) {
				boundsBuffered = new OpenLayers.Bounds();
			    boundsBuffered.extend(new OpenLayers.LonLat(bounds.left-buffer/2,bounds.bottom-buffer/2));
			    boundsBuffered.extend(new OpenLayers.LonLat(bounds.right+buffer/2,bounds.top+buffer/2));
			    // Estende il buffer fino a includere anche un buffer intorno ai marker
			    var b = this.routingMarkersLayer.getDataExtent();
			    boundsBuffered.extend(new OpenLayers.LonLat(b.left-buffer/2,b.bottom-buffer/2));
			    boundsBuffered.extend(new OpenLayers.LonLat(b.right+buffer/2,b.top+buffer/2));
			    
			    this.map.zoomToExtent(boundsBuffered);
			} else {
				this.map.zoomToExtent(bounds);
			}
		} else {
			var lonLat = bounds.getCenterLonLat();
			this.pluginGotoPosition(lonLat.lon, lonLat.lat, zoom, false);	
		}
		
		this.isAlreadyDrawn=true;	
	},
	     
	/**
	 * Method: pluginAddStartRoutingMarker
	 * Aggiunge il marker di inizio tracciato per il routing
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	 * Parameters:
	 * lon - {} longitudine
	 * lat - {} latitudine
	 * opts - {} opzioni
	 */
	pluginAddStartRoutingMarker: function(lon, lat, opts) {
		
		if (this.startMarker != null) {
			this.pluginClearStartRoutingMarker();
			//this.startMarker.geometry = new OpenLayers.Geometry.Point(lon, lat);
			//return;
		}
		
		var o = opts || {};
		
		TolomeoExt.applyIfEmpty(o, {
			icon	: this.TOLOMEOServer + this.TOLOMEOStaticRoot + 'img/ols/startPoint.png',
			widht	: 24,
			height	: 37,
			xOffset	: -12,
			yOffset	: -37,
			tooltip	: ToloI18n.getMsg("ToloViewerOLPanel.pluginAddStartRoutingMarker.tooltip")
		});
				
		this.startMarker = new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Point(lon, lat), {}, {
			externalGraphic	: o.icon,
			graphicWidth	: o.widht,
			graphicHeight	: o.height,
			graphicXOffset	: o.xOffset,
			graphicYOffset	: o.yOffset,
			title			: o.tooltip 
		});
		
		this.routingMarkersLayer.addFeatures( [this.startMarker] );
		this.pluginRoutingActivate();
	},
	
	/**
	 * Method: pluginClearViaRoutingMarkers
	 * Elimina tutti i marker di tappa intermedia tracciato per il routing
	 * Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	 *
	*/
	pluginClearStartRoutingMarker: function() {
		if (this.startMarker != null) {
			this.routingMarkersLayer.destroyFeatures(this.startMarker);
			this.startMarker = null;
		}
	},
		
	/**
	* Method: pluginAddEndRoutingMarker
	* Aggiunge il marker di fine tracciato per il routing
	* Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	*
	* Parameters:
	* lon - {} longitudine
	* lat - {} latitudine
	* opts - {} opzioni
	*/
	pluginAddEndRoutingMarker: function(lon, lat, opts) {
		if (this.endMarker != null) {
			this.pluginClearEndRoutingMarker();
			//this.endMarker.geometry = new OpenLayers.Geometry.Point(lon, lat);
			//return;
		}
		
		var o = opts || {};
		
		TolomeoExt.applyIfEmpty(o, {
			icon	: this.TOLOMEOServer + this.TOLOMEOStaticRoot + 'img/ols/endPoint.png',
			widht	: 24,
			height	: 37,
			xOffset	: -12,
			yOffset	: -37,
			tooltip	: ToloI18n.getMsg("ToloViewerOLPanel.pluginAddEndRoutingMarker.tooltip")
		});
			
		this.endMarker = new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Point(lon, lat), {}, {
			externalGraphic	: o.icon,
			graphicWidth	: o.widht,
			graphicHeight	: o.height,
			graphicXOffset	: o.xOffset,
			graphicYOffset	: o.yOffset, 
			title			: o.tooltip
		});
		
		this.routingMarkersLayer.addFeatures( [this.endMarker] );		
	},
	
   /**
	* Method: pluginClearViaRoutingMarkers
	* Elimina tutti i marker di tappa intermedia tracciato per il routing
	* Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	*
	*/
	pluginClearEndRoutingMarker: function() {
		if (this.endMarker != null) {
			this.routingMarkersLayer.destroyFeatures(this.endMarker);
			this.endMarker = null;
		}
	},
	
	/**
	* Method: pluginAddViaRoutingMarker
	* Aggiunge il marker di tappa intermedia tracciato per il routing
	* Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	*
	* Parameters:
	* lon - {} longitudine
	* lat - {} latitudine
	* opts - {} opzioni
	*/
	pluginAddViaRoutingMarker: function(id, lon, lat, opts) {
		var o = opts || {};
		
		TolomeoExt.applyIfEmpty(o, {
			icon	: this.TOLOMEOServer + this.TOLOMEOStaticRoot + 'img/ols/viaPoint.png',
			widht	: 24,
			height	: 37,
			xOffset	: -12,
			yOffset	: -37,
			tooltip	: ToloI18n.getMsg("ToloViewerOLPanel.pluginAddViaRoutingMarker.tooltip")
		});
			
		var viaMarker = new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Point(lon, lat), {
			id: id
		}, {
			externalGraphic	: o.icon,
			graphicWidth	: o.widht,
			graphicHeight	: o.height,
			graphicXOffset	: o.xOffset,
			graphicYOffset	: o.yOffset,
			title			: o.tooltip
		});  
			 
		this.routingMarkersLayer.addFeatures( [viaMarker] );		
		this.viaMarkers.push(viaMarker);
	},
		
	/**
	* Method: pluginClearViaRoutingMarkers
	* Elimina tutti i marker di tappa intermedia tracciato per il routing
	* Come tutte le funzioni con prefisso 'plugin' deve essere implementata in un plugin dedicato ad un certo viewer.
	*
	*/
	pluginClearViaRoutingMarkers: function() {
		this.routingMarkersLayer.destroyFeatures( this.viaMarkers );
		this.viaMarkers = [];
	},
		
	/**
	* Method: olViewerOnDragDropEndRouting
	* Metodo privato per la gestione dell'evento di drag delle geometrie di routing
	*
	* Parameters:
	* feature - {OpenLayers.Feature.Vector} feature soggetta a modifica
	*/
		olViewerOnDragDropEndRouting: function(feature)	{
			var	event;
			var startPoint = null;
			var endPoint = null;
			var viaPoint = null;
			var viaId = null;
			
			if (feature == this.startMarker) {
				event = 'startPointMoved';
				startPoint = this.startMarker ? new Point(this.startMarker.geometry.x, this.startMarker.geometry.y) : null;
			} else if (feature == this.endMarker) {
				event = 'endPointMoved';
				endPoint = this.endMarker ? new Point(this.endMarker.geometry.x, this.endMarker.geometry.y) : null;
			} else {
				event = 'viaPointMoved';
				viaPoint = new Point(feature.geometry.x, feature.geometry.y);
				viaId = feature.attributes.id;
			}
			
			this.fireEvent(event, startPoint, endPoint, viaPoint, viaId);
		}
    	
});

/**
 * Class: TolomeoExt.ToloViewerOLPanel.SelectFeatureControlManager
 * 
 * Clas to manage select feature for more layers
 *
 * Inherits from:
 *  - <Ext.Base>
 *
 */
Ext.define('TolomeoExt.ToloViewerOLPanel.SelectFeatureControlManager', {

    /**
     * @cfg {Object} map
     * The map is the Openlayers Map object with which to work
     */
	
    /**
     * @cfg {Object} viewer
     * The viewer is the TolomeoExt.ToloViewerOLPanel
     */

    /**
     * Creates new SelectFeatureManager.
     * @param {Object} config Config object.
     */
    constructor : function(config){
        this.initialConfig = config;
        this.map = config.map;
        this.viewer = config.viewer;        
        this.init();
    },
    
    layersMap : {},
	delegatorMap : {},
	selectControl: null, 	    		
	highlightControl: null,
	
	init: function(){

		var me = this;
		var viewer = this.viewer;
		
		this.selectControl = new OpenLayers.Control.SelectFeature(
                [],
                {
                	renderIntent: 'select',
                	
                	onBeforeSelect: function(feature){		 
                    	var callback = me.layersMap[feature.layer.name].callbacks.onBeforeSelect;
                		return callback ? callback(feature.layer.name,feature,viewer) : true;
                	},
                
                    onSelect: function(feature){
                    	var callback = me.layersMap[feature.layer.name].callbacks.onSelect;
                    	if(callback){
                    		callback(feature.layer.name,feature,viewer);
                    	}
                    },
                    
                    onUnselect: function(feature){
                    	var callback = me.layersMap[feature.layer.name].callbacks.onUnselect;
                    	if(callback){
                    		callback(feature.layer.name,feature,viewer);
                    	}
                    }                                                           
                }
        );
		
		this.highlightControl = new OpenLayers.Control.SelectFeature(
                [],
                {	                         
                    multiple:false, 
                    hover:true, 
                    highlightOnly:true,
                    renderIntent: 'temporary',
                    
                    eventListeners:{
                    	
                    	beforefeaturehighlighted : function(event){
                    		var callback = me.layersMap[event.feature.layer.name].callbacks.onBeforeHighlight;
                    		return callback ? callback(event.feature.layer.name,event.feature,viewer) : true;
                    	},                  
                    	
                        featurehighlighted: function (event) {
                        	var callback = me.layersMap[event.feature.layer.name].callbacks.onHighlight;
                        	if(callback){
                        		callback(event.feature.layer.name,event.feature,viewer);
                        	}
                        },
                        
                        featureunhighlighted: function (event) {
                        	var callback = me.layersMap[event.feature.layer.name].callbacks.onUnhighlight;
                        	if(callback){
                        		callback(event.feature.layer.name,event.feature,viewer);
                        	}
                        }
                    }	                           
                }
        );
		
		this.map.addControl(this.selectControl);
        this.map.addControl(this.highlightControl);
        
	},
	
	addDelegator : function(d){	  
		
		d.active = false;
		this.delegatorMap[d.id] = d;
		
		for(var i=0; i < d.layers.length ; i++){
			this.layersMap[d.layers[i].name] = d;			
		}
		
		if(d.moreControls){
			for(var i=0; i<d.moreControls.length; i++){								
				this.map.addControl(d.moreControls[i]);
			}
		}
	},
	
	activateDelegator : function(idP){		
		
		var delegator = this.delegatorMap[idP];
		if(!delegator.active){	    				
			this.deactivate();
			delegator.active = true;
			var layers = [];
			
			for(var i in this.delegatorMap){
				if(!this.delegatorMap.hasOwnProperty(i)) continue;
				var d = this.delegatorMap[i];
				if(d.active){
					layers = layers.concat(d.layers);
				}
			}
			
			this.selectControl.setLayer(layers);
			this.highlightControl.setLayer(layers);
			this.activate();
			
			if(delegator.callbacks.onActivate){
				delegator.callbacks.onActivate(this.viewer);
			}
		}
	},
	
	deactivateDelegator : function(idP){
		
		var delegator = this.delegatorMap[idP];
		
		if(delegator.active){	    	
			
			this.deactivate();
			delegator.active = false;
			var layers = [];
			
			for(var i in this.delegatorMap){
				if(!this.delegatorMap.hasOwnProperty(i)) continue;
				
				var d = this.delegatorMap[i]; 
				if(d.active){
					layers = layers.concat(d.layers);
				}	    					
			}
			
			if(layers.length > 0) {
				this.selectControl.setLayer(layers);
				this.highlightControl.setLayer(layers);				
				this.activate();
			} 
			
			if(delegator.callbacks.onDeactivate){
				delegator.callbacks.onDeactivate(this.viewer);
			}
		}
	},
	
	activate : function(){	    	
		
		this.highlightControl.activate();
		this.selectControl.activate();
		
		// Activate further controls of all active delegator
		for(var i in this.delegatorMap){
			if(!this.delegatorMap.hasOwnProperty(i)) continue;
			
			var d = this.delegatorMap[i];
			if(d.active && d.moreControls){
				for(var c=0; c<d.moreControls.length; c++){
					d.moreControls[c].activate();
				}
			}	    					
		}
		
	},
	
	deactivate : function(){
	
		// Deactivate further controls of all active delegator
		for(var i in this.delegatorMap){			
			if(!this.delegatorMap.hasOwnProperty(i)) continue;
			
			var d = this.delegatorMap[i];
			
			if(d.active && d.moreControls){
				for(var c=0; c<d.moreControls.length; c++){					
					d.moreControls[c].deactivate();				    				    				   
				}
			}	    					
		}
		
		this.selectControl.deactivate();
		this.highlightControl.deactivate();
	}
});


Ext.define('TolomeoExt.ToloViewerOLPanel.SelectFeatureControlManager.DelegatorWidget', {
	
	/**
     * @cfg {String} id
     * The unique id of this widget
     */
	
	/**
     * @cfg {Array} layers
     * The list of layers of the widget. 
     * To see the correct things whene feature of a layer are selected or highlighted, you need to define a styleMap for the layer
     * with the following keys
     * 	- default	(for normal style)
     * 	- select	(for selected style)
     *  - highlight	(forn highlighted style)
     */
	
    /**
     * @cfg {Object} callbacks
     * The viewer is the TolomeoExt.ToloViewerOLPanel
     */

	/**
     * @cfg {Object} moreControls
     * Further controls of the widget that Select Feature Control Manager have to activate or deactivate 
     * when SelectFeature ia activated or deactivated.
     * If there are further controls, but you don't pass them to the Select Feature Control Manager
     * you have to handle them by yourself
     */
	
	/**
     * @cfg {Object} callbacks
     * Object with all callbacks for the SelectFeatureControlManager
     * - onActivate 		: called when widget is activated
     * - onBeforeSelect 	: called before select a feature (return false to avoid selection)
     * - onSelect 			: called after feature selection
     * - onUnselect 		: called after deselection
     * - onBeforeHighlight	: called before highlight a feature (return false to avoid highlighting)
     * - onHighlight 		: called after highlighted
     * - onUnhighlight 		: called after unhighlight
     * - onDeactivate 		: called after widget is deactivated to finalize it
     */
	
    /**
     * Creates new SelectFeatureManager.
     * @param {Object} config Config object.
     */
    constructor : function(config){
        this.initialConfig = config;
        this.id = config.id;
        this.layers = config.layers;
        this.moreControls = config.moreControls;
        this.callbacks = config.callbacks;        
    }
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.namespace("TolomeoExt");

/**
 * Method: TolomeoExt.ToloAPIOpCodes
 *  
 */	
TolomeoExt.ToloAPIOpCodes = new function() {
	var contaBottoni = 0;
	
 	this.btnNuovo          = contaBottoni++;
 	this.btnNuovoDaLayer   = contaBottoni++;
 	this.btnNuovoDaImport  = contaBottoni++;
 	this.btnDelete         = contaBottoni++;
 	this.btnAdd            = contaBottoni++;
 	this.btnSubtract       = contaBottoni++;
 	this.btnAddSub         = contaBottoni++;
 	this.btnUpdateAlfa     = contaBottoni++;
 	this.btnIdentify       = contaBottoni++;
 	this.btnVertexEdit     = contaBottoni++;
 	this.btnDragDrop       = contaBottoni++;
 	this.btnTemporalFilter = contaBottoni++;
 	this.btnAutoIdentify   = contaBottoni++;

 	this.btnActionPanel2Max = contaBottoni-1;

 	this.btnLegenda	  = contaBottoni++;
 	this.btnRicerca   = contaBottoni++;
 	this.btnPan 	  = contaBottoni++;
 	this.btnPanNord   = contaBottoni++;
 	this.btnPanEst 	  = contaBottoni++;
 	this.btnPanSud 	  = contaBottoni++;
 	this.btnPanOvest  = contaBottoni++;
 	this.btnMeasure   = contaBottoni++;
 	this.btnSeleziona = contaBottoni++;
 	this.btnAnnullaSelezioni = contaBottoni++;

 	this.btnZoomIn  = contaBottoni++;
 	this.btnZoomOut = contaBottoni++;
 	this.btnZoomBox = contaBottoni++;
 	this.btnZoomAll = contaBottoni++;
 	
 	this.btnPrint            = contaBottoni++;
 	this.btnTimeMachine      = contaBottoni++;
 	this.btnSnap             = contaBottoni++;
 	this.btnCsw              = contaBottoni++;
 	this.btnWMSExplorer      = contaBottoni++;
 	this.btn3D      		 = contaBottoni++;
 	
 	this.btnHistoryPrev	 	= contaBottoni++;
 	this.btnHistoryNext	 	= contaBottoni++;
 	
 	//this.btnMostraCoordinate = contaBottoni++;

	// lasciare per ultimo (il codice assume che siano customButton quelli >= btnCustomBase
 	this.btnCustomBase = contaBottoni++;
}();/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloStreetviewViewerPanel
 * @extends Ext.Panel
 * Pannello ExtJs contenente un Google Panorama Street View
 * 
 */        
Ext.define('TolomeoExt.ToloStreetviewViewerPanel', {
		
	extend: 'Ext.Panel',
	
	/**
	 * @property {Number} posLon
	 * Longitudine posizione iniziale
	 * 
	 */
	posLon: null,
	
	/**
	 * @property {Number} posLat
	 * Latitudine posizione iniziale
	 * 
	 */
	posLat: null,
	
	/**
	 * @property {Object} heading
	 * Heading iniziale
	 * 
	 */
	heading: null,
	
	/**
	 * @property {Object} pitch
	 * Pitch iniziale
	 * 
	 */
	pitch: null,
	
	/**
	 * @property {Number} zoom
	 * Zoom iniziale
	 * 
	 */
	zoom: null,
	
	/**
	 * @property {Object} streetviewclient
	 * 
	 * 
	 */
	streetviewclient: null,
	
	/**
	 * @property {Object} panorama
	 * 
	 * 
	 */
	panorama: null,
	
	/**
	 * @method initComponent
	 * 
	 * 
	 */
	initComponent : function() {
		
		this.addEvents('onPositionChanged');
		this.addEvents('onPovChanged');
		this.addEvents('onLinksChanged');
		
		if (this.heading==null) this.heading=0;
		if (this.pitch==null) 	this.pitch=0;
		if (this.zoom==null) 	this.zoom=1;
        
        //	Create StreetViewClient for querying information about panorama
		this.streetviewclient = new google.maps.StreetViewService();
		
		this.bindToViewer(this.viewer);
		this.viewer.pluginAddStreetviewLayers();
		this.viewer.bindToStreetviewViewer(this);
		
		this.callParent(arguments);
		
	},
	
	/**
	 * @method bindToViewer
	 * 
	 * 
	 * @param {Object} viewer
	 * 
	 * 
	 */
	bindToViewer: function(viewer) {
		if (viewer) {
			viewer.on('onStreetviewDropComplete', this.setViewPosition, this);
			viewer.on('onStreetviewNavLinkClick', this.getPanoramabyId, this);
		}
	},
	
	/**
	 * @method getPanoramabyId
	 * 
	 * 
	 * @param {Object} panoId
	 * 
	 * 
	 */
	getPanoramabyId: function(panoId) {
		
		var delegateFn = Ext.Function.bind(this.getPanoramaByIdCallback, this);
		this.streetviewclient.getPanoramaById(panoId, delegateFn);
	   //this.streetviewclient.getPanoramaById(panoId, this.getPanoramaByIdCallback.createDelegate(this));
	},
	
	/**
	 * @method getPanoramaByIdCallback
	 * 
	 * 
	 * @param {Object} data
	 * 
	 * 
	 * @param {Object} streetviewstatus
	 * 
	 * 
	 */
	getPanoramaByIdCallback: function (data, streetviewstatus) {
		if (data) {
			if (streetviewstatus == "ZERO_RESULTS") {        //600 nessun panorama
                //this.deleteFeatures();
	    		//this.panorama.setVisible(false);
            } else if (streetviewstatus == "UNKNOWN_ERROR") { //500 errore
                //this.deleteFeatures();
	    		//this.panorama.setVisible(false);
            } else if (streetviewstatus == "OK") {            // 200 OK
            	var pov = {
            		heading: this.panorama.pov.heading,
            		pitch  : this.panorama.pov.pitch,
            		zoom   : this.panorama.pov.zoom
            	};
				this.setViewPosition(data.location.latLng.lng(), data.location.latLng.lat());
				this.panorama.setPov(pov);
            }
		} else {
            //this.deleteFeatures();
    		//this.panorama.setVisible(false);
        }
    },
	
	/**
	 * @method afterRender
	 * 
	 * 
	 */
	afterRender : function() {
		var pos = new google.maps.LatLng(this.posLat, this.posLon);
		var panoramaOptions = {
	    	position: pos,
	    	pov: {
	        	heading: this.heading,
	        	pitch  : this.pitch,
	        	zoom   : this.zoom
			}
	    }
		this.panorama = new google.maps.StreetViewPanorama(this.body.dom,panoramaOptions);
		this.on('resize', function() {google.maps.event.trigger(this.panorama, 'resize');});
		var thiswin = this;
		google.maps.event.addListener(this.panorama, 'position_changed', 
			function() {
				//alert("position_changed");
				var pos = thiswin.panorama.getPosition();
				var heading = thiswin.panorama.getPov().heading;
				thiswin.fireEvent('onPositionChanged', pos.lng(), pos.lat(), heading);
			});

		//Add panorama event listeners
    	google.maps.event.addListener(this.panorama, "pov_changed", 
    		function() {
				var pos = thiswin.panorama.getPosition();
				var heading = thiswin.panorama.getPov().heading;
				thiswin.fireEvent('onPovChanged', pos.lng(), pos.lat(), heading);
			}
    	);
				        
		google.maps.event.addListener(this.panorama, "links_changed", 
			function() {
				var links = thiswin.panorama.getLinks();
				var pos = thiswin.panorama.getPosition()
				thiswin.fireEvent('onLinksChanged', links, pos);
			}
		);

		this.callParent(arguments);
		
	},
	
	/**
	 * @method beforeDestroy
	 * 
	 * 
	 */
    beforeDestroy: function() {
        delete this.panorama;
        this.callParent(arguments);
    },
	
	/**
	 * @method setViewPosition
	 * 
	 * 
	 * @param {Number} lon
	 * 
	 * 
	 * @param {Number} lat
	 * 
	 * 
	 */
	setViewPosition: function (lon, lat) {
		var pos = new google.maps.LatLng(lat, lon);	
		this.panorama.setPosition(pos);
	} 
});
	/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloTOCAbstractDataProvider
 * @extends Ext.util.Observable
 * 
 * 
 */
Ext.define('TolomeoExt.ToloTOCAbstractDataProvider', {

	extend: 'Ext.util.Observable',
 
	/** 
	 * @property {String} TOLOMEOServer
	 * 
	 * 
	 */
	TOLOMEOServer: null,

	/** 
	 * @property {String} TOLOMEOContext
	 * 
	 * 
	 */
	TOLOMEOContext: null,

	/** 
	 * @property {Boolean} [isStyleCapable=false]
	 * Indica se il data provider prevede la gestione degli stili (es. mapserver no, WMS si )  
	 * 
	 */
	isStyleCapable: false,
	
	/**
	 * @constructor
	 * Crea un nuovo TolomeoExt.ToloTOCAbstractDataProvider.
	 *
	 * @param {Object} config
	 * The configuration
	 *
	 * @returns {TolomeoExt.ToloTOCAbstractDataProvider}
	 * Un nuovo TolomeoExt.ToloTOCAbstractDataProvider.
	 * 
	 */
	constructor: function(config) {		
		Ext.apply(this, config);
		//Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);	
		this.callParent();
	},
	
	/**
	 * @method initComponent
	 * 
	 * 
	 */
	initComponent: function(){ 
        this.addEvents('onFullDataRequestEnd');
        this.addEvents('onVisibleDataRequestEnd');
        
        /**
         * @event onRequestLayerInfoDataEnd
         * Viene emesso quando viene ricevuto la risposta ad una richiesta di layerInfo per un nuovo layer WMS
         * 
    	   * @param {Object} layInfo
    	   * struttura layerinfo relativa al WMS
    	   * 
	       * @param {Object} extra
	       * parametri extra
	       * 
         */
        this.addEvents('onRequestLayerInfoDataEnd');
        
		this.callParent(); 
    },

    
  /**
   * @method requestFullData
   * 
   * 
   * @param {Object} options
   * oggetto contenenti i parametri della richiesta.
	 * options.presetName - {string} nome del preset.
	 * options.currentMap - {string} mappa.
	 * options.scale - {number} valore di scala 	
	 * options.presetXML - {String} xml del file di preset.
	 * options.sendPreset - {boolean} abilitazione all'invio del preset
	 * 
	 */
    requestFullData: function(options) {    	
    	 
    },
    
    /**
     * @method fullDataRequestEnd
     * 
     * 
     * @param {Object} records
     * recordset.
     * 
     * @param {Object} opts
     * opts.
     * 
     */
    fullDataRequestEnd: function(records, scale) {
    	this.fireEvent('onFullDataRequestEnd', records, scale);
    },
    
    /**
     * @method requestVisibleData
     * 
     * 
     * @param {Object} nomePreset
     * nomePreset.
     * 
     * @param {Object} mappa
     * mappa.
     * 
     * @param {Object} scale
     * valore di scala.
     * 
     * @param {Object} tocInfo
     * 
     * 
     */
    requestVisibleData: function(nomePreset, mappa, scale, tocInfo) {
	   	
    },
    
    /**
     * @method visibleDataRequestEnd
     * 
     * 
     * @param {Object} opts
     * opts.
     * 
     * @param {Object} scale
     * 
     * 
     */
    visibleDataRequestEnd: function(obj, scale) {
    	this.fireEvent('onVisibleDataRequestEnd', obj, scale);
    },
    
    /**
     * @method requestLayerInfoDataEnd
     * Funzione di callback che riceve la struttura layerinfo realtiva ad un WMS
     * 
     * @param {Object} layInfo
     * struttura layerinfo relativa al WMS
     * 
     * @param {Object} extra
     * parametri extra
     * 
     */
    requestLayerInfoDataEnd: function(layInfo, extra) {
    	this.fireEvent('onRequestLayerInfoDataEnd', layInfo, extra);
    }
    
});





/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloTOCMultiServerProvider
 * 
 * 
 */
Ext.define('TolomeoExt.ToloTOCMultiServerProvider', {

	extend: 'TolomeoExt.ToloTOCAbstractDataProvider',
	
	alias: ['widget.tx_ToloTOCMultiServerProvider'],
	
	//requires: [],
	
	/** 
	 * @property {String} TOLOMEOServer
	 * 
	 * 
	 */
	TOLOMEOServer: null,

	/** 
	 * @property {String} TOLOMEOContext
	 * 
	 * 
	 */
	TOLOMEOContext: null,
	
	/** 
	 * @property {Object} paramsJS
	 * 
	 * 
	 */
	paramsJS : null,

	/**
	 * @method initComponent
	 * 
	 * 
	 */
	initComponent: function(){
		this.callParent();
    },

        
  /**
   * @method requestFullData
   * 
   * 
   * @param {Object} options
   * oggetto contenenti i parametri della richiesta.
	 * options.presetName - {string} nome del preset.
	 * options.currentMap - {string} mappa.
	 * options.scale - {number} valore di scala 	
	 * options.presetXML - {String} xml del file di preset.
	 * options.sendPreset - {boolean} abilitazione all'invio del preset
	 *   
   */
    requestFullData: function(options) {    	

    	this.requestFullData1(options); 
    	this.callParent(arguments);

    },
    
  /**
   * @method requestFullData1
   * 
   * 
   * @param {Object} options
   * oggetto contenenti i parametri della richiesta.
	 * options.presetName - {string} nome del preset.
	 * options.currentMap - {string} mappa.
	 * options.scale - {number} valore di scala 	
	 * options.presetXML - {String} xml del file di preset.
	 * options.sendPreset - {boolean} abilitazione all'invio del preset
	 *   
   */
    requestFullData1: function(options) {
    	//TOC mai attivata. Occorre costruirla
    	if (options.currentMap.legenda) {   
    		
    		var params = {
    			//scale:   scale ,
    			update: 'false', 
				tipoServer: 'wms',
				numMappaCorrente: '0'
			};
			
    		if(options.sendPreset &&  options.presetXML){
    			params.paramPresetString = options.presetXML;
    			params.presetName = options.presetName;
    		} else {
    			params.paramPreset = options.presetName;
    		}
    		
    		Ext.apply(params, this.paramsJS.urlAdditionalParams);
    		
    		var ajaxOptions = { 
					url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxTOCServletExt',
					method: 'post',
					params: params, //TODO per adesso gestita solo la prima mappa}
					success: function (records, opts) { 
									this.fullDataRequestEnd(records, opts, options.scale); 
								},
					failure: function (store, opts, records) {
							//TODO vedere se fare qualcosa in aggiunta al messaggio a video di defautl
					},
					scope: this
					//text: "Loading...",
					//TODO
					//failure: this.showAjaxError, 
				  }    		
    		
    		new TolomeoExt.ToloCrossAjax().request(ajaxOptions);  		
    	}
    },
    
    /**
     * @method fullDataRequestEnd
     * 
     * 
     * @param {Array} records
     * recordseset.
     * 
     * @param {Object} opts
     * opts.
     * 
     */
    fullDataRequestEnd: function(records, opts, scale) {
    	var obj = records[0].data;
    	this.callParent([obj, scale]);

    },
        
    /**
     * @method requestVisibleData
     * 
     * 
     * @param {Object} options
     * oggetto contenenti i parametri della richiesta.
  	 * options.presetName - {string} nome del preset.
  	 * options.currentMap - {string} mappa.
  	 * options.scale - {number} valore di scala 
	   * options.tocInfo - {object} struttura della TOC
  	 * options.presetXML - {String} xml del file di preset.
	   * options.sendPreset - {boolean} abilitazione all'invio del preset
     * 
     */
    requestVisibleData: function(options) {
		var sep=",";
		
		if (options.currentMap.legenda) {  
		
			var retObj = { layers: "", stili: "", layIdx: "", catIdx: "" };
			
			options.tocInfo.onEachLayer(
				function(cat, lay, catIdx, layIdx) {
					
					if (options.tocInfo.getLayerNeedRequestVisibleData(catIdx, layIdx)) {
						this.stili  += (this.layers!="" ? sep : "") + (lay.style=="" ? "null" : lay.style);
						this.layIdx += (this.layers!="" ? sep : "") + layIdx;
						this.catIdx += (this.layers!="" ? sep : "") + catIdx;
						this.layers += (this.layers!="" ? sep : "") + lay.name;	
					}
				},
				retObj
			);
	    	
			var thisDataProvider = this;
			
			var params = {
    			update: true,
				tipoServer: 'wms',
				layers: retObj.layers,
				stili: 	retObj.stili,
				catIdx:	retObj.catIdx,
				layIdx:	retObj.layIdx,
				random: Math.random(),
				numMappaCorrente: '0'
			};
			
    		if(options.sendPreset && options.presetXML){
    			params.paramPresetString = options.presetXML;
    			params.presetName = options.presetName;
    		} else {
    			params.paramPreset = options.presetName;
    		}
    		
    		Ext.apply(params, this.paramsJS.urlAdditionalParams);
	
			var ajaxOptions = { 
				url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxTOCServletExt',
				method: 'post',
				params: params, //TODO per adesso gestita solo la prima mappa} 
				success: function(records, opts) { 
					thisDataProvider.visibleDataRequestEnd(options.currentMap.legenda, options.scale, records, opts) 
				},
				//TODO
				//failure: this.showAjaxError,
				scope: this 
			}

    		new TolomeoExt.ToloCrossAjax().request(ajaxOptions);
		}
		this.callParent([options.scale]);
    },
    
    /**
     * @method visibleDataRequestEnd
     *
     * 
     * @param {Object} legenda
     * 
     * 
     * @param {Object} scale
     * 
     * 
     * @param {Object} records
     * 
     * 
     * @param {Object} opts
     * 
     * 
     * TODO dipendenza dalla scala per adesso staticamente definita in preset
     */
    visibleDataRequestEnd: function(legenda, scale, records, opts) {
    	
    	var obj = records[0].data;
    	this.callParent([obj, scale]);
    	
    },	
	
    /**
     * @method requestLayerInfoData
     * 
     * 
     * @param {Object} options
     * oggetto contenenti i parametri della richiesta.
  	 * options.presetName - {string} nome del preset.
  	 * options.currentMap - {string} mappa.
  	 * options.scale - {number} valore di scala 
	   * options.tocInfo - {object} struttura della TOC
  	 * options.presetXML - {String} xml del file di preset.
	   * options.sendPreset - {boolean} abilitazione all'invio del preset
     * 
     */
	requestLayerInfoData: function(options) {
    		
		var params = {
			//scale:   scale ,
			serverurl: options.serverurl, 
			layername: options.layername
		};
		
		Ext.apply(params, this.paramsJS.urlAdditionalParams);
		
		var ajaxOptions = { 
				url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxTOCLayerInfoServlet',
				method: 'post',
				params: params, 
				success: function (records, opts, extra) { 
								this.requestLayerInfoDataEnd(records, opts, options.extra);				
							},
				failure: function (store, opts, records) {
						//TODO vedere se fare qualcosa in aggiunta al messaggio a video di defautl
				},
				scope: this

			  }    		
		
		new TolomeoExt.ToloCrossAjax().request(ajaxOptions);  		   		
    }, 
    
    /**
     * @method requestLayerInfoDataEnd
     * Funzione di callback che riceve la struttura layerinfo realtiva ad un WMS
     * 
     * @param {Object} records
     * Record dello store. Contiene un solo oggetto
     * 
     * @param {Object} opts
     * Opzioni
     * 
     * @param {Object} extra
     * parametri extra
     * 
     */
    requestLayerInfoDataEnd: function(records, opts, extra) {
    	var obj = records[0].data;
    	this.callParent([obj, extra]);
    }
    
});





/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * @class TolomeoExt.ToloTOCPanelExt
 * @extends Ext.Panel
 * Pannello per contenere una mappa. 
 * 
 */
Ext.define('TolomeoExt.ToloTOCPanelExt', {

	extend: 'Ext.Panel',
	
	
	/** 
	 * @property {Object} lastUsedLocalCodTPN
	 * 
	 * 
	 */
	lastUsedLocalCodTPN: null,
	
	/** 
	 * @property {Object} dataProvidcerOpt
	 * 
	 * 
	 */
	dataProvidcerOpt: null,
	
	/** 
	 * @property {Boolean} showHideContainer
	 * Contenitore che deve essere
	 * mostrato/nascosto per visualizzare o nascondere la legenda Se null
	 * viene visualizzato e nascosto questo stesso pannelleo
	 * 
	 */
	showHideContainer : null,

	/** 
	 * @property {Function} showHandler
	 * Funzione da chiamare per visualizzare la legenda. Se null non viene chiamata
	 * 
	 */
	showHandler : null,

	/** 
	 * @property {Function} hideHandler
	 * Funzione da chiamare per nascondere la legenda. Se null non viene chiamata
	 * 
	 */
	hideHandler : null,

	/** 
	 * @property {Boolean} isTOCVisible
	 * 
	 * 
	 */
	isTOCVisible : null,

	/** 
	 * @property {Object} paramsJS
	 * 
	 * 
	 */
	paramsJS : null,

	/** 
	 * @property {Object} dataProvider
	 * 
	 * 
	 */
	dataProvider : null,

	/** 
	 * @property {Object} tocInfo
	 * 
	 * 
	 */
	tocInfo : null,

	/** 
	 * @property {String} TOLOMEOServer
	 * 
	 * 
	 */
	TOLOMEOServer : null,

	/** 
	 * @property {String} TOLOMEOContext
	 * 
	 * 
	 */
	TOLOMEOContext : null,

	/** 
	 * @property {Object} scale
	 * scala attuale aggiornata ad ogni chiamata di creazione o aggiornamento TOC da parte di metodi invocati da API
	 * si è reso necessario per gestione cambio stile
	 * 
	 */
	scale: null,
	
	/** 
	 * @property {String} iconBasePath
	 * 
	 * 
	 */
	iconBasePath:null, 
	
	
	/** 
	 * @property {Object} customQuery
	 * 
	 * 
	 */
	customQuery: null,
	

	/**
	 * @method initComponent
	 * Metodo relativo alla gestione Ext.
	 * 
	 */
	initComponent : function() {

		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		this.isTOCCreated = false;
		this.isFullDataRequested = false;
		this.isTOCGUICreated = false;
		
		if (this.dataProviderOpt==null) this.dataProviderOpt={}; 
	
		// decide il tipo di dataprovider da utilizzare se non definito
		// modificato per utilizzare il multiserver
		var dpxtype = "widget.tx_ToloTOCMultiServerProvider";
		// ...anche nel caso che venissero forzati i dataprovider attualmente esistenti   
		if ((this.dataProviderOpt.xtype=='tx_toloTOCMapServerDataProvider') || (this.dataProviderOpt.xtype=='tx_toloTOCGeoserverDataProvider')) {
			this.dataProviderOpt.xtype = dpxtype;
		}
		
		/*
		switch (this.getParametriMappaCurr().typeCode) {
			case 0: 	// Mapserver
				dpxtype = 'tx_toloTOCMapServerDataProvider';
				break;
			case 11:	// WMS
				dpxtype = 'tx_toloTOCGeoserverDataProvider';	
				break;
			default:
				// data provider non definito
				
		}*/
		
		TolomeoExt.applyIfEmpty(this.dataProviderOpt, {
				TOLOMEOServer: this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext,				
				paramsJS : this.paramsJS,
				xclass: dpxtype 		//'tx_toloTOCMapServerDataProvider'
			});
		
		// se definito tipo di dataprovider lo creo
		if (dpxtype!='') this.dataProvider = Ext.create(this.dataProviderOpt);
		
		
		// TODO Events
		// TODO ? this.addEvents('layerSelectionChange');
		// TODO ? this.addEvents('categorySelectionChange');
		// TODO ? this.addEvents('categoryEnableChange');
		this.addEvents('layerCheckedChange');
		this.addEvents('categoryCheckedChange');
		this.addEvents('layerOpacityChange');
		this.addEvents('layerOrderChange');
		this.addEvents('layerStyleChanged');
		
		this.addEvents('categoryExpand');
		this.addEvents('categoryCollapse');
		this.addEvents('layerExpand');
		this.addEvents('layerCollapse');
		
		/**
		 * @event stylePanelRequest
		 * Lanciato quando viene richiesta la visualizzazione del pannello di gestione degli stili
		 * @param {String} nome nome layer
		 * @param {Number} cat numero categoria del layer 
		 * @param {Number} lay numero del layer
		 * @param {String[][]} 	Elenco degli stili definiti per il layer nella forma [[stile1],[stile2]] 
		 * 
		 */
		this.addEvents('stylePanelRequest');
		this.addEvents('ajaxError');
		this.addEvents('tocCreate');
		this.addEvents('tocGuiCreate');

		this.addEvents('contextMenuZoomToExtent');
		this.addEvents('contextMenuShowInfo');
		this.addEvents('contextMenuZoomMaxScaleMax');
		this.addEvents('contextMenuZoomMinScaleMin');
		
		this.addEvents('contextMenuAddWMSFromCatalogClick');
		
		/**
		 * @event contextMenuMetadataClick
		 * Lanciato quando viene scelta la voce del menu di contesto relativa al metadato del layer
		 * @param {Object}  Oggetto javascript contenente i campi format, type e url
		 */
		this.addEvents('contextMenuMetadataClick');
		
		this.addEvents('exportForQgisClicked');
		
		
		//this.addEvents('contextMenuAddCategory');
		//this.addEvents('contextMenuAddLayer');
		
		/**
		 * @event layerLinkClick
		 * Lanciato quando viene clickato una voce di legenda corrispondente ad un layer
		 * @param  {Number} cat indice della categoria
		 * @param  {Number} lay indice del layer
		 */
	//	this.addEvents('layerLinkClick');
	//	this.addEvents('categoryLinkClick');
		
		
		this.addEvents('categoryAdded');
		this.addEvents('layerAdded');
		
		this.addEvents('itemSelected');
		this.addEvents('itemClicked');
		this.addEvents('addLayerToQgisClicked');
		
		this.dataProvider.on('onFullDataRequestEnd', this.onFullDataRequestEnd, this);
		this.dataProvider.on('onVisibleDataRequestEnd', this.onVisibleDataRequestEnd , this);
		this.dataProvider.on('onRequestLayerInfoDataEnd', this.addLayerCallback , this);
		
		
		this.tocInfoField = new Ext.form.TextField({
	    	name: 'tocInfo'
	    });
	    							
	    this.paramsJSField = new Ext.form.TextField({
	    	name: 'paramsJS'
	    });
		
		this.nMappaField = new Ext.form.TextField({
			name: 'nMappa'
		});
		
		this.idxCategoriaBase = new Ext.form.TextField({
			name: 'idxCategoriaBase'
		});
		
		this.idxLayerBase = new Ext.form.TextField({
			name: 'idxLayerBase'
		});

	    this.submitForm = new Ext.form.FormPanel({
			hidden: true,
			renderTo: Ext.getBody(),
			bodyStyle: 'position:absolute; top: 0px; left 0px;',
			standardSubmit: true,
			method: 'POST',
			items: [this.tocInfoField, this.paramsJSField, this.layerOrderField, this.nMappaField, this.idxCategoriaBase, this.idxLayerBase]
	    });		
	    
		
	    if (this.iconBasePath==null) this.iconBasePath =  TolomeoExt.Vars.TOLOMEOServer + TolomeoExt.Vars.TOLOMEOStaticRoot + 'img/icone/16-default/';

		this.callParent();
		//TolomeoExt.ToloTOCPanelExt.superclass.initComponent.call(this);
	},

	/**
	 * @method onFullDataRequestEnd
	 * 
	 * 
	 * @param {Object} obj
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 */
	onFullDataRequestEnd: function(obj, scale) {
		
		var legenda = this.getParametriMappaCurr().legenda;
		var objBuff = {};
		Ext.apply(objBuff, obj);
		Ext.apply(objBuff, { presetLegenda: legenda});
		var a = [];
		
		this.tocInfo = new TolomeoExt.ToloTOCInfo(objBuff);
		
		this.tocInfo.on("catTreeIdxUpdate", this.onTOCInfoCatTreeIdxUpdate, this);
		this.tocInfo.on("layTreeIdxUpdate", this.onTOCInfoLayIdxUpdate, this);
		
		if (legenda) {
			this.tocInfo.onEachLayer(
				function(cat, lay, catIdx, layIdx) { 
					lay.checked = lay.defaultGroup;
					if (lay.temporaryNotAvailable) a.push({catIdx: catIdx, layIdx: layIdx});
					lay.parentcategorychecked = cat.checked;
					lay.layId = cat.catId + "-" + lay.descr;
					var tocInfo = this.tocInfo;
					lay.isEnabled = function(){
						
						if (/* tocInfo.areAllParentCatChecked(catIdx) */ tocInfo.areAllParentCatChecked(cat.catTreeIdx) && cat.checked){
							//return this.parentcategorychecked && this.checked; 
							//return this.checked;
							return this.checked;
						}else{
							//return this.checked;
							return false;
						}
					}
					
					var layer = this.tocInfo.getCategoryPresetInfo(catIdx).layerList[layIdx];
					
					var smin = (layer) ? layer.scalaMinima : -1;
    				var smax = (layer) ? layer.scalaMassima : -1;
					
					lay.visible=this.layerIsVisibleAtScale(scale, smin, smax, lay.minScaleMin, lay.maxScaleMax );

				},
				this
			);
			
		}
		
		this.createTOC(scale);
		for (var i=0; i<a.length; i++) {
			this.setLayerStateChange(a[i].catIdx, a[i].layIdx, false, true);	
		}
		
	},
	
	/**
	 * @method onVisibleDataRequestEnd
	 * 
	 * 
	 * @param {Object} obj
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 */
	onVisibleDataRequestEnd: function(obj, scale) {
		this.updateTocInfoFromVisibleRequest(obj, scale);
		this.updateTOC(scale);
	},
	
	/**
	 * @method showTOC
	 * Visualizza la legenda. La legenda deve essere stata precedentemente creata ed aggornata ai cambi scala con createOrUpdate
	 * 
	 */
	showTOC : function() {

		if (this.isTOCCreated) {
			// solo visualizzare ed aggiornare
			this.isTOCVisible = true;
	
			if (this.showHandler != null) {
				this.showHandler.call(this);
			} else if (this.showHideContainer != null) {
				this.showHideContainer.setVisible(this.isTOCVisible);
			} else
				this.setVisible(this.isTOCVisible);
	
			// setta anche eventuali container
			/*
			 * ct=this.ownerCt; while (ct) { ct.setVisible(this.isTOCVisible);
			 * ct=ct.ownerCt; }
			 */
		}
		
	},

	/**
	 * @method hideTOC
	 * 
	 * 
	 */
	hideTOC : function() {
		if (this.isTOCVisible != null) {
			this.isTOCVisible = false;
			if (this.hideHandler != null) {
				this.hideHandler.call(this);
			} else if (this.showHideContainer != null) {
				this.showHideContainer.setVisible(this.isTOCVisible);
			} else
				this.setVisible(this.isTOCVisible);
		}
	},

	/**
	 * @method createTOC
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 */
	createTOC : function(scale) {
		this.scale=scale;
		this.isTOCCreated = true;
		this.fireEvent('tocCreate');
	},

	/**
	 * @method updateTOC
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 */
	updateTOC : function(scale, posObj) {
		if (scale != undefined) this.scale=scale;
		if (posObj != undefined) this.posObj = posObj;
		this.updateTocInfoVisibleAtScale(scale);
	},
	
	/**
	 * @method createOrUpdate
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 * @param {Boolean} forceRequest
	 * se true forza la richiesta al server dei layer visibili alla scala indicata, altrimenti la legenda viene aggiornata con i dati disponibili
	 * 
	 */
	createOrUpdate: function(scale, forceRequest, posObj) {		
		if (scale != undefined) this.scale  = scale;
		if (posObj != undefined) this.posObj = posObj;
		if (this.isFullDataRequested) {
			//this.requestVisibleData(scale);
			// TODO scelta per casi nei quali va richiesto l'aggiornamento al server come in caso di cambi di stile
			var thisPanel = this;
			if (!this.isTOCCreated) {
				setTimeout(function() {	thisPanel._requestOrUpdate(scale, forceRequest); },4500);
			} else {
				this._requestOrUpdate(scale, forceRequest);
			}
		} else {
			this.requestFullData(scale);
		}		
	},

	/**
	 * @method _requestOrUpdate
	 * @private
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 * @param {Boolean} forceRequest
	 * 
	 * 
	 */
	_requestOrUpdate: function(scale, forceRequest) {
		if (forceRequest) {
			this.requestVisibleData(scale); 
		} else {
			this.updateTOC(scale);
		}
	},
	
	/**
	 * @method requestFullData
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 */
	requestFullData : function(scale) {
		this.scale=scale;
		this.isFullDataRequested = true; 
		var parametriMappaCurr = this.getParametriMappaCurr();
		if (parametriMappaCurr.legenda) {
			var options = {
				presetName: this.paramsJS.nomePreset, 
				currentMap: parametriMappaCurr, 
				scale: scale,
				presetXML: this.presetXML,
				sendPreset: this.sendPreset
			};
						
			this.dataProvider.requestFullData(options);
		}
	},

	/**
	 * @method requestVisibleData
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 */
	requestVisibleData : function(scale) {
		this.scale=scale;
		var parametriMappaCurr = this.getParametriMappaCurr();
		if (parametriMappaCurr.legenda) {
			var options = {
				presetName: this.paramsJS.nomePreset, 
				currentMap: parametriMappaCurr, 
				scale: scale,
				tocInfo: this.tocInfo,
				presetXML: this.presetXML,
				sendPreset: this.sendPreset
			};	
					
			this.dataProvider.requestVisibleData(options);
		}
	},

	/**
	 * @method getScaleMinMaxFromIdxs
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 */
	getScaleMinMaxFromIdxs: function(catIdx, layIdx) {
	
		var lay = this.tocInfo.getCategoryInfo(catIdx).layers[layIdx]
		var layerPresetInfo = this.tocInfo.getCategoryPresetInfo(catIdx).layerList[layIdx];
		
		var smin = (layerPresetInfo) ? layerPresetInfo.scalaMinima : -1;
    	var smax = (layerPresetInfo) ? layerPresetInfo.scalaMassima : -1;
		
		return this.getScaleMinMax( smin, smax, lay.minScaleMin, lay.maxScaleMax);
		
	},
	
	/**
	 * @method getScaleMinMax
	 * 
	 * 
	 * @param {Object} legendaScalaMinima
	 * 
	 * 
	 * @param {Object} legendaScalaMassima
	 * 
	 * 
	 * @param {Object} styleMinScaleMin
	 * 
	 * 
	 * @param {Object} styleMaxScaleMax
	 * 
	 * 
	 */
	getScaleMinMax: function(legendaScalaMinima, legendaScalaMassima, styleMinScaleMin, styleMaxScaleMax) {
		
		var scalaMinima  = legendaScalaMinima;
		var scalaMassima = legendaScalaMassima;
		
		if ((scalaMinima ==undefined)||(scalaMinima ==null)||(scalaMinima ==-1)) {
			// Se non definito su preset conta quello da stile
			scalaMinima = styleMinScaleMin;
		} 
		
		if ((scalaMassima ==undefined)||(scalaMassima ==null)||(scalaMassima ==-1)) {
			// Se non definito su preset conta quello da stile
			scalaMassima = styleMaxScaleMax;
		} 
		
		return {scalaMinima: scalaMinima, scalaMassima: scalaMassima};
		
	},
	
	/**
	 * @method layerIsVisibleAtScale
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 * @param {Object} legendaScalaMinima
	 * 
	 * 
	 * @param {Object} legendaScalaMassima
	 * 
	 * 
	 * @param {Object} styleMinScaleMin
	 * 
	 * 
	 * @param {Object} styleMaxScaleMax
	 * 
	 * 
	 */
	layerIsVisibleAtScale: function(scale,legendaScalaMinima, legendaScalaMassima, styleMinScaleMin, styleMaxScaleMax) {
    	
		var scala = this.getScaleMinMax(legendaScalaMinima, legendaScalaMassima, styleMinScaleMin, styleMaxScaleMax);
		
		var scalaMinima  = scala.scalaMinima;
		var scalaMassima = scala.scalaMassima;
		
		if (((scalaMinima ==undefined)||(scalaMinima ==null)||(scalaMinima ==-1)||(scalaMinima <= scale)) &&
		    ((scalaMassima==undefined)||(scalaMassima==null)||(scalaMassima==-1)||(scale <= scalaMassima))) {
			visible = true;
		} else {
			visible = false;
		}
		
		return visible;
	     
    },	

	/**
	 * @method updateTocInfo
	 * Aggiorna la struttura TocInfo con il risultato di una richiesta di update
	 * 
	 * @param {Object} visibleStateInfo
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 */
	updateTocInfoFromVisibleRequest : function(visibleStateInfo, scale) {
		var legenda = this.getParametriMappaCurr().legenda;
		if (this.tocInfo && this.tocInfo.presetLegenda) {	
			for (var i = 0; i < visibleStateInfo.layers.length; i++) {
				var lay = visibleStateInfo.layers[i].lay;
				var cat = visibleStateInfo.layers[i].cat;
				this.tocInfo.setLayerNeedRequestVisibleData(cat, lay, false);
				var categoria = this.tocInfo.getCategoryPresetInfo(cat);
				var layer = categoria.layerList[lay]; // info sul layer da preset
				this.tocInfo.getCategoryInfo(cat).layers[lay].minScaleMin = visibleStateInfo.layers[i].minScaleMin;
				this.tocInfo.getCategoryInfo(cat).layers[lay].maxScaleMax = visibleStateInfo.layers[i].maxScaleMax;
				if (visibleStateInfo.layers[i].urlLegendaClasseUnica != undefined && 
						visibleStateInfo.layers[i].urlLegendaClasseUnica!=null && 
						visibleStateInfo.layers[i].urlLegendaClasseUnica!="") {
					this.tocInfo.getCategoryInfo(cat).layers[lay].classi[0].nome = visibleStateInfo.layers[i].urlLegendaClasseUnica;
				}
			}
		}
	},
	
	/**
	 * @method updateTocInfoVisibleAtScale
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 */
	updateTocInfoVisibleAtScale: function(scale) {
	
		if (this.tocInfo && this.tocInfo.presetLegenda)
		this.tocInfo.onEachLayer(
				function(cat, lay, catIdx, layIdx) { 
					
					var categ = this.tocInfo.getCategoryPresetInfo(catIdx);
					if (categ!=undefined && categ!=null) { 
						var layer = categ.layerList[layIdx];
						lay.visible = this.layerIsVisibleAtScale(scale, layer.scalaMinima, layer.scalaMassima, lay.minScaleMin, lay.maxScaleMax );
					}
					else  lay.visible = this.layerIsVisibleAtScale(scale, -1, -1, lay.minScaleMin, lay.maxScaleMax );
				},
				this
		);
		
	},
	
	/**
	 * @method setLayerStateChange
	 * 
	 * 
	 * @param {Object} cat
	 * cat.
	 * 
	 * @param {Object} lay
	 * lay.
	 * 
	 * @param {Object} checked
	 * checked.
	 * 
	 * @param {Object} force
	 * se true forza l'operazione anche se lo stato da impostare è uguale a quello attuale
	 * 
	 */
	setLayerStateChange : function(cat, lay, checked, force) {
		
		 
		if (this.tocInfo != null) {
			if (lay != null) {
				// Aggiorna la struttura in memoria
				this.tocInfo.getCategoryInfo(cat)
				var layer = this.tocInfo.getCategoryInfo(cat).layers[lay];
				if(!force && layer.checked == checked) return;
				layer.checked = checked;
				
				// Nel caso di catagoria mutuamente esclusiva, se ho acceso questo layer spengo tutti gli altri
				if (checked==true) {
					var legenda = this.getParametriMappaCurr().legenda;
					
					if (legenda && this.tocInfo.getCategoryPresetInfo(cat).mutualExclusive && this.tocInfo.getCategoryPresetInfo(cat).mutualExclusive==true) {
						for (var i=0; i < this.tocInfo.getCategoryInfo(cat).layers.length; i++) {
							if (i!=lay) this.setLayerStateChange(cat, i, false);
						}
					}
					
					// nel caso di categoria mutualExclusiveCategoriesOnLayers 
					// disattivo gli altri layer delle altre categorie sorelle con 
					// mutualExclusiveCategoriesOnLayers a true
					var parentCategory = this.tocInfo
							.getCategoryInfo(this.tocInfo
							.getParentCategoryIdx(cat));
				
					
					if (parentCategory) {
						if (legenda
								&& this.tocInfo
								.getCategoryPresetInfo(cat).mutualExclusiveCategoriesOnLayers
								&& this.tocInfo
								.getCategoryPresetInfo(cat).mutualExclusiveCategoriesOnLayers == true) 
							{
								for (var i = 0; i < parentCategory.categories.length; i++) 
								{
									if (parentCategory.categories[i].catTreeIdx != cat
											&& this.tocInfo.getCategoryPresetInfo(parentCategory.categories[i].catTreeIdx)
											.mutualExclusiveCategoriesOnLayers
											&& this.tocInfo.getCategoryPresetInfo(parentCategory.categories[i].catTreeIdx)
											.mutualExclusiveCategoriesOnLayers == true) 
									{
										for (var s=0; s < parentCategory.categories[i].layers.length; s++) 
										{	
											var layInfo = this.tocInfo.getCategoryPresetInfo(parentCategory.categories[i].catTreeIdx).layerList[s];
											if (layInfo.hidden!=true && layInfo.userSwitchable!=false) 
											{
												this.setLayerStateChange(parentCategory.categories[i].catTreeIdx, s, false);	
											}
										}
									}
								}
							}

					} else {
						if (legenda
								&& this.tocInfo
								.getCategoryPresetInfo(cat).mutualExclusiveCategoriesOnLayers
								&& this.tocInfo
								.getCategoryPresetInfo(cat).mutualExclusiveCategoriesOnLayers == true) 
						{
							for (var i = 0; i < this.tocInfo.categories.length; i++) 
							{
								if (this.tocInfo.categories[i].catTreeIdx != cat
									&& this.tocInfo.getCategoryPresetInfo(this.tocInfo.categories[i].catTreeIdx)
										.mutualExclusiveCategoriesOnLayers
									&& this.tocInfo.getCategoryPresetInfo(this.tocInfo.categories[i].catTreeIdx)
										.mutualExclusiveCategoriesOnLayers == true)
								{
									for (var s=0; s < this.tocInfo.getCategoryInfo(this.tocInfo.categories[i].catTreeIdx).layers.length; s++) 
										{
											var layInfo = this.tocInfo.getCategoryPresetInfo(this.tocInfo.categories[i].catTreeIdx).layerList[s];
											if (layInfo.hidden!=true && layInfo.userSwitchable!=false) 
											{
												this.setLayerStateChange(this.tocInfo.categories[i].catTreeIdx, s, false);
											}		
									    }
							    }
						    }
					    }
					
					}
				}				

				this.fireEvent('layerCheckedChange',layer, this.tocInfo);
				
			} else {
				this.setCategoryStateChange(cat,checked);				
			}
		}		
	},
	
	/**
	 * @method setCategoryStateChange
	 * 
	 * 
	 * @param {Object} cat
	 * cat.
	 * 
	 * @param {Object} checked
	 * checked.
	 * 
	 */
	setCategoryStateChange : function(cat, checked) {
		if (this.tocInfo != null) {
			var category = this.tocInfo.getCategoryInfo(cat);
			
			category.checked = checked;

			if (checked == true) {
				var legenda = this.getParametriMappaCurr().legenda;
				var parentCategory = this.tocInfo
						.getCategoryInfo(this.tocInfo
								.getParentCategoryIdx(cat));

				if (parentCategory) {
					if (legenda
							&& this.tocInfo
									.getCategoryPresetInfo(this.tocInfo
											.getParentCategoryIdx(cat)).mutualExclusiveCategories
							&& this.tocInfo
									.getCategoryPresetInfo(this.tocInfo
											.getParentCategoryIdx(cat)).mutualExclusiveCategories == true) {
						for (var i = 0; i < parentCategory.categories.length; i++) {
							if (parentCategory.categories[i].catTreeIdx != cat) {
								this
										.setCategoryStateChange(
												parentCategory.categories[i].catTreeIdx,
												false);
							}
						}
					}
				} else {
					if (legenda
							&& this.tocInfo.presetLegenda.mutualExclusiveCategories
							&& this.tocInfo.presetLegenda.mutualExclusiveCategories == true) {
						for (var i = 0; i < this.tocInfo.categories.length; i++) {
							if (this.tocInfo.categories[i].catTreeIdx != cat) {
								this
										.setCategoryStateChange(
												this.tocInfo.categories[i].catTreeIdx,
												false);
							}
						}
					}
				}
			}

			this.fireEvent('categoryCheckedChange', category,
					this.tocInfo);
		}		
	},

	/**
	 * @method setAllLayersState
	 * Imposta allo stato passato tutti i layer in maniera non ricorsiva e senza modificare lo stato dei layer hidden.
	 * 
	 * @param {Object} cat
	 * cat.
	 * 
	 * @param {Object} checked
	 * checked.
	 * 
	 */
	setAllLayersState: function(cat, checked) {
		if (this.tocInfo != null) {
			this.tocInfo.onEachLayer(
					function(cat, lay, catIdx, layIdx) {
						//userSwitchable
						var layInfo = this.tocInfo.getCategoryPresetInfo(catIdx).layerList[layIdx];
						if (layInfo.hidden!=true && layInfo.userSwitchable!=false) {
							this.setLayerStateChange(catIdx, layIdx, checked);	
						}
					},					
					this, cat, false); 
		}
	},
	
	/**
	 * @method layerOrderChange
	 * 
	 * 
	 */
	layerOrderChange: function() {
		this.fireEvent('layerOrderChanged', this.tocInfo);
	},

	/**
	 * @method showAjaxError
	 * TODO gestire errori
	 * 
	 * @param {Object} transport
	 * 
	 * 
	 */
	showAjaxError : function(transport) {
		Ext.MessageBox.show({
			title: ToloI18n.getMsg("ToloTOCPanelExt.showAjaxError.title"),
			msg: ToloI18n.getMsg("ToloTOCPanelExt.showAjaxError.msg"),
			buttons: {
				yes: ToloI18n.getMsg("ToloTOCPanelExt.showAjaxError.btnMostra"),
				cancel: ToloI18n.getMsg("ToloTOCPanelExt.showAjaxError.btnContinua")
			},
			icon: Ext.MessageBox.ERROR,
			fn: function(btn) {
				switch (btn) {
					case 'yes':
						Ext.MessageBox.alert(ToloI18n.getMsg("ToloTOCPanelExt.showAjaxError.title"),
								transport.responseText);
						break;
				}
			}
		});
		
		this.fireEvent('ajaxError', transport);
	},

	/**
	 * @method getCurrTOCSettings
	 * 
	 * 
	 * @returns {Object}
	 * legenda
	 * 
	 */
	getCurrTOCSettings : function() {
		return this.getParametriMappaCurr().legenda;
	},

	/**
	 * @method getParametriMappaCurr
	 * 
	 * 
	 * @returns {Object}
	 * Restituisce i parametri correnti della mappa.
	 * 
	 */
	getParametriMappaCurr : function() {
		//TODO gestisce solo prima mappa
		return this.paramsJS.mappe.mappaList[0];
	},

	/**
	 * @method layerIsVisible
	 * Se il layer non è in legenda si suppone che sia visibile sempre.
	 * 
	 * @returns {Boolean}
	 * true if layer is visible
	 * 
	 */
	layerIsVisible : function(codTPN) {
		var bPresente = false;

		if (this.tocInfo) {
			
			var returnObj = { bPresente:false, bVisible: false };
			
			this.tocInfo.onEachLayer(
				function(cat, lay, catIdx, layIdx) {
					if (lay.codTPN == codTPN) {
						if ((lay.isEnabled()) && lay.visible ) { //this.layerIsScaleVisible(codTPN) 
							this.bPresente= true;
							this.bVisible = true;
						} else {
							this.bPresente = true;
							this.bVisible = false;
						}
					}
				},
				returnObj
			
			);
		
			return (!returnObj.bPresente || returnObj.bVisible )
		}
	},
	
	/**
	 * @method getVisibleLayers
	 * Restituisce la lista ordinata dei codici dei layers visibili.
	 * 
	 * @returns {Array}
	 * lista dei layers visibili
	 * 
	 */
	getVisibleLayers : function() {
		
		var visibleLayers = [];		

		var returnObj = { visibleLayers: visibleLayers, tocInfo: this.tocInfo };
		
		if (this.tocInfo.layerOrder && this.tocInfo.layerOrder.length>0) {
			
			for (var i = 0; i < this.tocInfo.layerOrder.length; i++) {
				var laypos = this.tocInfo.layerOrder[i];
				var cat = this.tocInfo.getCategoryInfo(laypos.cat);
				var lay = cat.layers[laypos.lay];
				
				if ( this.tocInfo.areAllParentCatChecked(laypos.cat) && cat.checked && lay.checked && lay.visible ){ 
					visibleLayers.push(lay);
				}
			}
			
		} else {
		
			this.tocInfo.onEachLayer(
				function(cat, lay, catIdx, layIdx) {
					if ( this.tocInfo.areAllParentCatChecked(catIdx) && cat.checked && lay.checked && lay.visible ){ 
						this.visibleLayers.push(lay);
					}
				},
				returnObj
			);

		}
		return returnObj.visibleLayers;
	},
	
	/**
	 * @method setLayerVisibility
	 * 
	 * 
	 * @param {Object} codTPN
	 * 
	 * 
	 */
	setLayerVisibility : function(codTPN) {
		
		if (!this.layerIsVisible(codTPN)) {
			if (this.tocInfo) {
				this.tocInfo.onEachLayer(
						function(cat, lay, catIdx, layIdx) {
							if (lay.codTPN == codTPN) {
								
								this.checkAllParentCat(catIdx, true);
								if (!lay.checked){
									this.setLayerStateChange(catIdx, layIdx, true);
								}
							}
						},
						this
					);
			}
		}
		
	}, 
	
	/**
	 * @method checkAllParentCat
	 * Accende tutte le categorie antenato della categoria indicata, più eventualmente la categoria stessa
	 * 
	 * @param {String} catIdx
	 * Indice della categoria della quale devono essere accesi tutti i parent
	 * 
	 * @param {Boolean} withCurrent
	 * indica se deve essere accesa anche la categoria corrente (catIdx). Default=false
	 * 
	 */
	checkAllParentCat: function(catIdx, withCurrent) {
		
		var bAllChecked = this.tocInfo.areAllParentCatChecked(catIdx);				
		if (!bAllChecked) {
			this.tocInfo.onEachParentCategory(
					function(cat1,catIdx1) {
						this.setCategoryStateChange(catIdx1, true);
					}, 
					this,
					catIdx); 
		}
		if (withCurrent) {
			var cat = this.tocInfo.getCategoryInfo(catIdx);
			if (!cat.checked ){
				this.setCategoryStateChange(catIdx, true);
			}
		}
	
		
	},
	
	/**
	 * @method setLayerStyle
	 * 
	 * 
	 * @param {Object} cat
	 * 
	 * 
	 * @param {Object} lay
	 * 
	 * 
	 * @param {Object} style
	 * 
	 * 
	 */
	setLayerStyle: function (cat, lay, style) {
		
		var layer = this.tocInfo.getCategoryInfo(cat).layers[lay];
		layer.style = style;
		this.tocInfo.setLayerNeedRequestVisibleData(cat, lay, true);
		this.createOrUpdate(this.scale, true, this.posObj);
		this.fireEvent('layerStyleChanged', layer, style);
	},
	
	/**
	 * @method setPresetXML
	 * 
	 * 
	 * @param {Object} presetXML
	 * 
	 * 
	 */
	setPresetXML: function(presetXML){
		this.presetXML = presetXML;
	},
	
	/**
	 * @method getContextMenu
	 * 
	 * 
	 * @param {Object} cat
	 * 
	 * 
	 * @param {Object} lay
	 * 
	 * 
	 */
	getContextMenu: function(cat, lay) {
		
		// TODO Gestisce solo mappa 0
		var nMappa = 0;
		
		var me = this;
		
		var layInfo = null;
		var catInfo = this.tocInfo.getCategoryInfo(cat)
		if (lay) layInfo = catInfo.layers[lay];
		var isLayer = layInfo && layInfo.itemType=='layer';
		var isCategory = (lay==undefined || lay==null) && catInfo && catInfo.itemType=='category';
		
		var menu = Ext.create('Ext.menu.Menu',{
		    cls: "clearCSS"
		});
		
		if (isLayer) {
			menu.add({
		    			text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuinfo"),
		    			//disabled: (this.tocInfo.getBoundingBox(cat, lay)==null),
		    			listeners: { click: {
    							fn: function() { this.fireEvent('contextMenuShowInfo', cat,lay, this.tocInfo); },
    							scope: this
    							}
    						}
		    		});
			
			//if (this.tocInfo.getCategoryPresetInfo(cat).layerList[lay].attribution) {
			if (layInfo.attribution) {
				menu.add({
	    			text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuattr"),
	    			//disabled: (this.tocInfo.getBoundingBox(cat, lay)==null),
	    			listeners: { click: {
							//fn: function() { Ext.MessageBox.alert('Attribuzioni', this.tocInfo.getCategoryPresetInfo(cat).layerList[lay].attribution ); },
	    					fn: function() { Ext.MessageBox.alert(ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuattr.title"), layInfo.attribution.title ); },
							scope: this
							}
						}
	    		});
			}
			
			var mdList = layInfo.metadataUrlList;
			if (mdList && mdList.length>0) {
				var mdItems = [];
				for (var i = 0; i < mdList.length; i++) {
					var md = mdList[i];
					mdItems.push({
							toloMetadata: md,
	    	    			text: md.type,
	    	    			listeners: { click: {
	    	    							fn: function() { 
	    	    									me.fireEvent('contextMenuMetadataClick', this.toloMetadata);
	    	    								}
	    	    							}
	    	    						}	    	    		
						});
				}
				var menuMetadata = Ext.create('Ext.menu.Item',
						{
							text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnumeta"),
							menu: {
								items: mdItems,
				    	    	 cls: "clearCSS"
								}
							});
				menu.add(menuMetadata);
			}
			
		}
		
		if (isCategory) {
			var menuAccendiSpegni = Ext.create('Ext.menu.Item',
					{
						text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuacc"),
						menu: {
							items: [{
			    	    			text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuacc.atutto"),
			    	    			disabled: this.tocInfo.getCategoryPresetInfo(cat).mutualExclusive,
			    	    			listeners: { click: {
			    	    							fn: function() { this.setAllLayersState(cat, true); },
			    	    							scope: this
			    	    							}
			    	    						}
			    	    			},{
				    	    			text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuacc.stutto"),
				    	    			listeners: { click: {
				    	    							fn: function() { this.setAllLayersState(cat, false); },
				    	    							scope: this
				    	    							}
				    	    						}
				    	    			}],
			    	    	 cls: "clearCSS"
							}
						});
			
			menu.add(menuAccendiSpegni);
			
			if ((this.paramsJS.layOut.csw || this.paramsJS.layOut.WMSExplorer)) {
				
				var menuAggiungi = Ext.create('Ext.menu.Item',
									{
										text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuagg"),
										menu: {
											items: [/*{
														text: "Aggiungi WMS da catalogo",
														listeners: { click: {
																		fn: function() {
																			this.fireEvent("contextMenuAddWMSFromCatalogClick", cat, lay, false);
																		}, 
																		scope: this
																		}
														}
													},{
														text: "Aggiungi WMS da server",
														listeners: { click: {
																		fn: function() {
																			this.fireEvent("contextMenuAddWMSFromWMSWidgetClick", cat, lay, false);
																		}, 
																		scope: this
																		}
														}
													},*/
													{
										    			text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuagg.cat"),
										    			//disabled: (this.tocInfo.getBoundingBox(cat, lay)==null),
										    			listeners: { click: {
								    							fn: function() {
									    								if (lay==null) {
									    									var msgbox = Ext.Msg.prompt(ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuagg.cat.title"), 
									    											ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuagg.cat.msg"),
								    										function(btn, catName) {
								    											if (btn!='cancel') {
										    										var catInfo = {
												    									paramsJSParams: {
												    										catDescr: catName,
												    										layerList: [],
												    										categoryList: [],
																							nome: catName,
																							userSwitchable: true
												    									},
												    									tocInfoParams: {
												    										catDescr: catName,
																							catId: catName +Math.random(),
																							//catTreeIdx: "0",
																							categories: [],
																							checked: false,	
																							clickTarget: "",
																							clickUrl: "",	
																							expanded: false,
																							forceClickable: false,
																							hidden: false,
																							layers: [],
																							nome: catName,	
																							toolTip: "",
																							userSwitchable: true
												    									}
																					};
												    								this.addCategory(catInfo, cat, false);
								    											}
								    										}, this);
									    								}
									    							},
								    							scope: this
								    							}
								    						}
										    		}],
							    	    	 cls: "clearCSS"
											}
										});
		
				if (this.paramsJS.layOut.csw) {
					menuAggiungi.menu.add({
								text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuagg.wmsdacat"),
								listeners: { click: {
												fn: function() {
															this.fireEvent("contextMenuAddWMSFromCatalogClick", cat, lay, false);
														}, 
												scope: this
											}
								}
							});
				}
			
			}
		
			if (this.paramsJS.layOut.WMSExplorer) {
				menuAggiungi.menu.add({
						text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuagg.wmsdaser"),
						listeners: { click: {
										fn: function() {
											this.fireEvent("contextMenuAddWMSFromWMSWidgetClick", cat, lay, false);
										}, 
										scope: this
										}
						}
					});
			}
			
			menu.add(menuAggiungi);			
		}
		
		if (isCategory || isLayer) {
			
			if (lay!=null) {
				
				var menuZoom = Ext.create('Ext.menu.Item',
						{
							text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuzoom"),
							menu: {
								items: [{
				    	    			text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuzoom.est"),
				    	    			disabled: (this.tocInfo.getBoundingBox(cat, lay)==null),
				    	    			listeners: { click: {
				    	    							fn: function() { this.fireEvent('contextMenuZoomToExtent', cat,lay, this.tocInfo); },
				    	    							scope: this
				    	    							}
				    	    						}
				    	    			}],
				    	    	 cls: "clearCSS"
								}
							});

				menuZoom.menu.add({
				    			text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuzoom.min"),
				    			disabled: !(layInfo.minScaleMin != undefined && layInfo.minScaleMin!=null && layInfo.minScaleMin > 0),
				    			listeners: { click: {
				    							fn: function() { this.fireEvent('contextMenuZoomMinScaleMin', cat,lay, this.tocInfo, this.getScaleMinMaxFromIdxs(cat, lay)); },
				    							scope: this
				    							}
				    						}
				    		});
				menuZoom.menu.add({
								text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuzoom.max"),
								disabled: !(layInfo.maxScaleMax != undefined && layInfo.maxScaleMax!=null && layInfo.maxScaleMax > 0 ),
								//disabled: (this.tocInfo.getBoundingBox(cat, lay)==null),
								listeners: { click: {
												fn: function() { this.fireEvent('contextMenuZoomMaxScaleMax', cat,lay, this.tocInfo, this.getScaleMinMaxFromIdxs(cat, lay)); },
												scope: this
												}
											}
							});
		
				menu.add(menuZoom);
				
				if (this._chkIfStyleManagerAvailable(layInfo)) {
					
					var menuStili = Ext.create('Ext.menu.Item',
							{
								text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnustili"),
								menu: {
									//items: [vociStili],
					    	    	 cls: "clearCSS"
									}
								});
				
					for (var i=0; i < layInfo.definedStyles.length ; i++) {
						
						var infoStile = layInfo.definedStyles[i];
						var s = Ext.create('Ext.menu.CheckItem',
							{
								text: (infoStile.title && infoStile.title!="") ? infoStile.title : infoStile.name,
								checked: infoStile.name==layInfo.style, 
								group: 'a',
								stile: infoStile.name,
								listeners: { click: { fn: function() { me.setLayerStyle(cat, lay, this.stile); }} }
								});
						menuStili.menu.add(s);
						
					}
					
					menuStili.menu.add('-');
					
					var manager = Ext.create('Ext.menu.Item',
							{
								text:  ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnustili.gest"),
								listeners: { click: { fn: function() { this.openStyleManager(cat, lay); }, scope: this} }
								});
					menuStili.menu.add(manager);
							
					menu.add(menuStili);
				}
	
				//if (layInfo.withOpacitySettings ) {					
				var sl = new Ext.slider.Single({
	    	     	 		    vertical: false,
	    	     	 		    value: (layInfo.opacity!=undefined && layInfo.opacity!=null )?  layInfo.opacity*100 : 100,
	    	     	 		    //increment: 10,
	    	     	 		    minValue: 0,
	    	     	 		    maxValue: 100	     	 	
	    	     	 		});	
				sl.on('change', function(slider, newValue, thumb, eOpts) { this.layerOpacityChange(cat, lay, newValue ); } , this);
	    	     	 		
				
				var menuTrasparenza = Ext.create('Ext.menu.Item',
												{
													text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnutrasp"),
													menu: {
														items: [sl],
										    	    	 cls: "clearCSS"
														}
													});		
				menu.add(menuTrasparenza);
				
				// Abilita miglioramento immagine se browser lo supporta
				if (Modernizr.cssfilters) {
					
					var enhanceEffects = ToloParamsJS.enhanceEffects;
					var menuEnhance = Ext.create('Ext.menu.Item',
							{
								text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuenha"),
								menu: {
									
					    	    	 cls: "clearCSS"
									}
								});		
					
					for (var i=0; i<enhanceEffects.length; i++) {
						var effect = enhanceEffects[i];
						var layInfoValue =  layInfo[effect.key];
						//alert('pippo');
						//alert ((layInfoValue!=undefined && layInfoValue!=null )?  layInfoValue * effect.scale : effect.defaultValue * effect.scale); 
						var menuBuff = Ext.create('Ext.menu.Item',
							{
								text: effect.getName(),
								menu: {
									items: [new Ext.slider.Single({
							     	 		    vertical: false,
							      	 		    value: (layInfoValue!=undefined && layInfoValue!=null )?  layInfoValue * effect.scale : effect.defaultValue * effect.scale ,
							      	 		    //increment: 10,
							      	 		    effect: effect,
							      	 		    minValue: effect.minValue,
							      	 		    maxValue: effect.maxValue * effect.scale,
							      	 		    listeners: {
							      	 		    		change: { fn: function(slider, newValue, thumb, eOpts){
							      	 		    								this.layerEnhanceChange(slider.effect, cat, lay, newValue );
							      	 		    							},
							      	 		    				  scope: this}
							      	 		    },
							      	 		    restoreDefaultValue: function() {
							      	 		    	this.setValue(this.effect.defaultValue * this.effect.scale );
							      	 		    }
							      	 		}),
							      	 		{
												xtype: 'menuitem',
												text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.mnuenha.reset"),
												listeners: {
														click: { fn: function(item, e, eOpts) {
																	var slider = item.up().down('slider');
																	slider.restoreDefaultValue();
																	},
																scope: this
														}
												}}
							      	 		],
					    	    	 cls: "clearCSS"
									}
								});		
						menuEnhance.menu.add(menuBuff)
						
					}
					menu.add(menuEnhance);
				}
				
				//}
			}
			
			if ((lay==null || this.paramsJS.isQGISExportable(nMappa, cat, lay))) {				
				if(this.paramsJS.layOut.conExportQGIS){
					menu.add(this.getExportMenuItem(cat, lay));
				}
				
				if(this.j2qConnected){
					menu.add({
		    			text: ToloI18n.getMsg("ToloTOCPanelExt.getContextMenu.addqgis"),
		    			iconCls : 'iconAddLayerToQGis',
						cls : "clearCss",					
		    			listeners: { click: {
		    							fn: function() { 
		    									this.fireEvent('addLayerToQgisClicked',cat,lay);																
		    							},
		    							scope: this
		    						}
		    					}
		    			});
				 }
			}
				    
		}
						
        return (menu.items.getCount()>0) ? menu : null;
		
	}, 
	
	
	
	/*
	 * @method getExportMenuItem
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 */
	getExportMenuItem: function(catIdx, layIdx) {
		
		return Ext.create('Ext.menu.Item', {
			text : ToloI18n.getMsg("ToloTOCPanelExt.getExportMenuItem.espo"),
			menu : {
				cls: 'clearCSS',
				items : [{
						xtype: 'menuitem',
						text: ToloI18n.getMsg("ToloTOCPanelExt.getExportMenuItem.espo.qgis"),
						iconCls : 'iconExportForQGis',
						menu:{
							cls: 'clearCSS',
							items: [
								{
									text: ToloI18n.getMsg("ToloTOCPanelExt.getExportMenuItem.espo.qgis180"),
			    	    			iconCls : 'iconExportForQGis',
									cls : "clearCss",
									listeners: { 								
										click: {
											fn: function() {     	    								
												this.fireEvent('exportForQgisClicked',null,null, "1.8.0");																												
											},
											scope: this
							    		}
							    		
									}	
								},{
									text: ToloI18n.getMsg("ToloTOCPanelExt.getExportMenuItem.espo.qgis2180"),
			    	    			iconCls : 'iconExportForQGis',
									cls : "clearCss",
									listeners: { 								
										click: {
											fn: function() {     	    								
												this.fireEvent('exportForQgisClicked',null,null, "2.18.0");																												
											},
											scope: this
							    		}
							    		
									}	
								}
							
							]
						}
					}]
			}
		});
		/*
		return Ext.create('Ext.menu.Item',
							{
								text: 'Export',
								menu: {
									items: [{
				    	    			text: 'Qgis',
				    	    			iconCls : 'iconExportForQGis',
										cls : "clearCss",
				    	    			listeners: { click: {
				    	    							fn: function() { 
				    	    									this.fireEvent('exportForQgisClicked',catIdx, layIdx);
				    	    							},
				    	    							scope: this
				    	    						}
				    	    					}
				    	    			}],
					    	    	 cls: "clearCSS"
									}
								});*/    	

	},
	
	/*
	 * @method layerOpacityChange
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 * @param {Object} newValue
	 * 
	 * 
	 */
	layerOpacityChange: function(catIdx, layIdx, newValue ) {
		//var nomeLayer = this.tocInfo.getCategoryInfo(cat).layers[lay].name;
		var oldValue = this.tocInfo.getCategoryInfo(catIdx).layers[layIdx].opacity;
		this.tocInfo.getCategoryInfo(catIdx).layers[layIdx].opacity=newValue/100;
    	this.fireEvent('layerOpacityChange', catIdx, layIdx, newValue/100, oldValue, this.tocInfo);

	},

	/**
	 * @method layerEnhanceChange
	 * @param {Object} effect
	 * @param {Object} catIdx
	 * @param {Object} layIdx
	 * @param {Object} newValue
	 * 
	 */
	layerEnhanceChange: function(effect, catIdx, layIdx, newValue ) {
		//var nomeLayer = this.tocInfo.getCategoryInfo(cat).layers[lay].name;
		var oldValue = this.tocInfo.getCategoryInfo(catIdx).layers[layIdx][effect.key];
		var newValueScaled = newValue/effect.scale;
		this.tocInfo.getCategoryInfo(catIdx).layers[layIdx][effect.key] = newValueScaled;
    	this.fireEvent('layerEnhanceChange', effect, catIdx, layIdx, newValueScaled, oldValue, this.tocInfo);

	},
	
	/*
	 * @method calcolaIconCls
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 * @param {Object} visible
	 * 
	 * 
	 */
    calcolaIconCls: function(catIdx, layIdx, visible ) {
    	var bConIcone = false;
    	
    	if (layIdx==null) {
    		// Categorie
    		//var cat = this.tocInfo.getCategoryInfo(catIdx);
	    	var iconCls="iconLegendaCategoria";
    	} else {
    		// Layer
			var lay = this.tocInfo.getCategoryInfo(catIdx).layers[layIdx];
	    	
	    	var iconCls="";
	    	if (lay.temporaryNotAvailable) {
	    		// se necessario warning accende icona su questo layer anche se non sarebbero normalemente visibili
	    		bConIcone = true;
	    		iconCls = "iconLegendaWarning";
	    	} else {
	    		if (visible) {
	    			iconCls = (lay.raster) ? "iconLegendaLayerRaster" : "iconLegendaLayerVector" ;	
	    		} else {
	    			iconCls = "iconLegendaLayerNotVisibleAtScale";
	    		}
	    		
	    	}
    	}
	
    	return { iconCls: iconCls, forzaConIcone: bConIcone };
    }, 
    
	/*
	 * @method calcolaLayerClickUrl
	 * 
	 * 
	 * @param {Object} lay
	 * 
	 * 
    calcolaLayerClickUrl: function (lay) {
    	
    	    	
    	if (lay.clickUrl) {
    		var params = "";
        	params += (lay.codTPN) ? "codTPN=" + lay.codTPN : "";
        	params += ((params!="") ? "&" : "") + "catIdx=" +lay.catTreeIdx;  
        	params += ((params!="") ? "&" : "") + "layIdx=" +lay.layTreeIdx;
        	
        	
        	
        	
        	var retVal = lay.clickUrl;
        	if (params!="") {
        		retVal += ((retVal.indexOf("?")==-1) ? "?" : "&")  + params ;	
        	} 
        	
        	return retVal;
    	} else {
    		return undefined;
    	}
    },
	 */
    
	/*
	 * @method calcolaCatToolTip
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 */
    calcolaCatToolTip: function (catIdx) {
    	
    	var cat = this.tocInfo.getCategoryInfo(catIdx)
    	var retVal = "";
    	
    	if (cat.toolTip && cat.toolTip!="") {
    		retVal = cat.toolTip;
    	} else {
    		retVal += '<ul class="legendaCatTooltip">';
    		for (var i=0; i<cat.categories.length; i++) {
    			if (cat.hidden!=undefined && cat.hidden!=null && cat.hidden==false) retVal += '<li class="legendaCatTooltipCat">' + cat.categories[i].catDescr + "</li>";
			}
    		for (var i=0; i<cat.layers.length; i++) {
    			var classCss = (cat.layers[i].raster && cat.layers[i].raster==true) ? "legendaCatTooltipLayVect" : "legendaCatTooltipLayRast";
    			if (cat.layers[i].hidden!=undefined && cat.layers[i].hidden!=null && cat.layers[i].hidden==false) retVal += '<li class="' + classCss + '">' + cat.layers[i].descr + "</li>";
			}
    	}
    	    		
        return retVal;
    },
    
	/*
	 * @method calcolaLayToolTip
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 */
    calcolaLayToolTip: function (catIdx, layIdx) {
    	
    	var lay = this.tocInfo.getCategoryInfo(catIdx).layers[layIdx]
    	var layerPresetInfo = this.tocInfo.getCategoryPresetInfo(catIdx).layerList[layIdx];
    	
    	var smin = (layerPresetInfo) ? layerPresetInfo.scalaMinima : -1;
    	var smax = (layerPresetInfo) ? layerPresetInfo.scalaMassima : -1;
    	
    	var scala = this.getScaleMinMax( smin, smax, lay.minScaleMin, lay.maxScaleMax);
		
		var scalaMinima  = scala.scalaMinima;
		var scalaMassima = scala.scalaMassima;
		
    	
    	var retVal = undefined;
    	    	
    	if (lay.toolTip && lay.toolTip!="") {
    		retVal = lay.toolTip;
    	} else {
    		retVal = lay.descr;
    	}
    	
    	if (scalaMassima!=undefined && scalaMassima!=null && scalaMassima!=-1) {
    		retVal += ToloI18n.getMsg("ToloTOCPanelExt.calcolaLayToolTip.smax", {scalaMassima: Math.round(scalaMassima)});  
    	}
    	
    	if (scalaMinima!=undefined && scalaMinima!=null && scalaMinima!=-1 && scalaMinima!=0) {
    		retVal += ToloI18n.getMsg("ToloTOCPanelExt.calcolaLayToolTip.smin", {scalaMinima: Math.round(scalaMinima)})  
    	}
    	
        return retVal;
    },
    
	/*
	 * @method onItemSelected
	 * 
	 * 
	 * @param {Object} catTreeIdx
	 * 
	 * 
	 * @param {Object} layTreeIdx
	 * 
	 * 
	 * @param {Object} classi
	 * 
	 * 
	 */
    onItemSelected: function(catTreeIdx, layTreeIdx, classi) {
    	this.fireEvent('itemSelected', catTreeIdx, layTreeIdx, classi);
    },
    
	/*
	 * @method onItemClicked
	 * 
	 * 
	 * @param {Object} catTreeIdx
	 * 
	 * 
	 * @param {Object} layTreeIdx
	 * 
	 * 
	 * @param {Object} classi
	 * 
	 * 
	 * @param {Object} e
	 * 
	 * 
	 */
    onItemClicked: function(catTreeIdx, layTreeIdx, classi, e) {
    	if (classi!=null) {
    		this.openStyleManager(catTreeIdx, layTreeIdx);
    	}
    	this.fireEvent('itemClicked', catTreeIdx, layTreeIdx, classi, e);
    },
    
    /**
     * @method openStyleManager
     * Richiede l'apertura della finestra di scelta di uno stile alternativo
     * 
  	 * @param {Object} catIdx
  	 * 
  	 * 
  	 * @param {Object} layIdx
  	 * 
  	 * 
     */
    openStyleManager: function(catIdx, layIdx) {
    	var cat = this.tocInfo.getCategoryInfo(catIdx);
    	var lay = cat.layers[layIdx];
    	
		if (this._chkIfStyleManagerAvailable(lay)) {
			this.fireEvent('stylePanelRequest', 
							lay,
							catIdx,
							layIdx,
							lay.definedStyles
							)
		}
	},
	
    /**
     * @method _chkIfStyleManagerAvailable
     * @private
     * 
     * 
  	 * @param {Object} layInfo
  	 * 
  	 * 
     */
	_chkIfStyleManagerAvailable: function(layInfo) {
		return layInfo.styleCapable && layInfo.definedStyles.length>0;
	},
	
	/**
	 * @method addCategory
	 * Aggiunge una categoria nella posizione indicata dai parametri.
	 * 
	 * @param {Object} catInfo
	 * Categoria da aggiungere
	 * 
	 * @param {Object} addPointCatIdx
	 * categoria prima o dopo della quale va aggiunta la roba
	 * 
	 * @param {Object} bBefore
	 * indica se aggiungere prima o dopo 
	 * 
	 */
	addCategory: function(catInfo, addPointCatIdx, bBefore) {
		
		var addPointCat = this.tocInfo.getCategoryInfo(addPointCatIdx);
		var addPointCatId = addPointCat.catId;
		
		// TODO Gestisce solo mappa 0
		var nMappa = 0;
		
		// Setto flag che indica che è una categoria utente
		catInfo.paramsJSParams.isUserCategory = true;
		catInfo.tocInfoParams.isUserCategory  = true;

		
		this.paramsJS.addCategory(nMappa, catInfo.paramsJSParams, addPointCatIdx, bBefore);
		this.tocInfo.addCategory(catInfo.tocInfoParams, addPointCatIdx, bBefore);
		
		this.addCategoryExtend(catInfo, addPointCat, bBefore);
		
		// Se c'è un ordine diverso da quello iniziale lo ricrea da zero (la nuova categoria provoca rinumerazione 
		if (this.tocInfo.layerOrder && this.tocInfo.layerOrder.length>0) this.tocInfo.layerOrder = this.createOrRefreshLayerOrder();
		
		this.fireEvent('categoryAdded', this.tocInfo, catInfo);
		
	},
	
	/**
	 * @method addCategoryExtend
	 * Metodo astratto da estendere per gestire a livello di singola tipologia di legenda l'aggiunta della categoria per esempio nella GUI.
	 * 
 	 * @param {Object} catInfo
 	 * Categoria da aggiungere
 	 * 
	 * @param {Object} bBefore
	 * indica se aggiungere prima o dopo
 	 * 
	 * @param {Object} addPointCat
	 * categoria prima o dopo della quale va aggiunta la roba
 	 * 
	 */
	addCategoryExtend: function(catInfo, addPointCat, bBefore ) {
		
	},
	
	/**
	 * @method addLayer
	 * Aggiunge un layer nella posizione indicata dai parametri.
	 * 
	 * @param {Object} options
	 * oggetto contenente le opzioni nei seguenti attributi <br />
	 * <ul>
	 * 	<li>serverurl: url del server WMS</li>
	 * 	<li>layername: nome del layer WMS</li>
	 * 	<li>addPointCatIdx: Indice della categoria nella quale viene aggiunto il layer </li>
	 * 	<li>addPointLayIdx: Indice layer prima o dopo del quale aggiungere il nuovo layer</li>
	 *  <li>where: indica se aggiungere prima (0), dopo (1), dentro (2)</li>
	 * </ul>
	 * 
	 */
	addLayer: function(options) {
		
		this.dataProvider.requestLayerInfoData({ 
				serverurl: options.serverurl, //"http://dvpgeoserver.comune.prato.it/geoserver/ows?service=wms&version=1.1.1&request=GetCapabilities",
				layername: options.layername,  //"comunepo:generica_circoscrizioni"
				extra: {
						serverurl: options.serverurl,
						layername: options.layername,
						addPointCatIdx: options.addPointCatIdx,
	 					addPointLayIdx: options.addPointLayIdx, 
	 					bBefore: options.where
					}
		});
		
	},
	
	/**
	 * @method addLayerCallback
	 * Funzione di callback per la richiesta di informazioni di un layer da inserire
	 * 
	 * @param {Object} layTocInfo
	 * Informazioni sul layer (struttura TOCLayerBean) ricevuta dal server
	 * 
	 * @param {Object} extra
	 * parametri extra
	 * 
	 */
	addLayerCallback: function(layTocInfo, extra) {
	
		var paramsInfo= {
			serverID: null,
			name: extra.layername,
		    hidden: false,
		    userSwitchable: true,
		    codTPN: 0,
		    defaultLayer: true,
		    withOpacitySettings: false,
		    iconaLegenda: null,
		    descrizione: layTocInfo.descr,
		    defaultStyle: "",
		    scalaMinima: -1,  // Influenza solo lo stato della visualizzazione nella legenda (nero o grigio), non l'effettiva visualizzazione.
		    								    // Utilizzato solo nel caso di WMS generico o di GEOSERVER senza REST, cioè nei casi nei quali non è possibile ottenere lo stato di visibilità in funzione della scala. Ignorato negli altri casi 
			scalaMassima: -1,  // Influenza solo lo stato della visualizzazione nella legenda (nero o grigio), non l'effettiva visualizzazione.
		     									// Utilizzato solo nel caso di WMS generico o di GEOSERVER senza REST, cioè nei casi nei quali non è possibile ottenere lo stato di visibilità in funzione della scala. Ignorato negli altri casi
			extraLegendGraphPar: null, 	
			catTreeIdx: null,
			layTreeIdx: null,
			raster: false,
			clickUrl: null,
			clickTarget: null,
			stiliIndipDaScala: true,
			toolTip: null,
			expanded: false,
			opacity: null,
			itemType: 'layer',
			queryable: layTocInfo.queryable,
			getFeatureInfoFormats: layTocInfo.getFeatureInfoFormats
		};
		
		var serverInfo = {		
			id						: null,
			nome 					: null,
			typeDescription       	: "WMS",
			typeCode             	: 11,
			nomeCredenziale   		: null,
			allowServerConnection 	: true,
			url          		  	: extra.serverurl,
			usaProxyPer3D			: true,
			serverOpts				: null,
			tilesMultiple 			: false,
			tileStampaAltezza		: null,
			tileStampaLarghezza		: null,
			noTolomeoParams			: false,
			opacity					: 1.0
		}
	
		this.addLayerByLayerInfo(paramsInfo, layTocInfo, serverInfo, extra.addPointCatIdx, extra.addPointLayIdx, extra.bBefore);
		
	},
	
	/**
	 * @method addLayerByLayerInfo
	 * Aggiunge un layer nella posizione indicata dai parametri. Se addPointLayIdx non è definito il punto di inserimento è una categoria
	 * 
	 * @param {Object} paramsInfo
	 * Info relative al layer da inserire in paramsJS
	 * 
	 * @param {Object} layTocInfo
	 * Tocinfo del layer da aggiungere
	 * 
	 * @param {Object} serverInfo
	 * Info sul server del layer da inserire
	 * 
	 * @param {Object} addPointCatIdx
	 * Indice della categoria nella quale viene aggiunto il layer 
	 * 
	 * @param {Object} addPointLayIdx
	 * Indice layer prima o dopo del quale aggiungere il nuovo layer
	 * 
	 * @param {Object} bBefore
	 * indica se aggiungere prima o dopo
	 */
	addLayerByLayerInfo: function(paramsInfo, layTocInfo, serverInfo, addPointCatIdx, addPointLayIdx, bBefore) {

		// Recupera categoria e layer di inserimento
		var addPointCat = this.tocInfo.getCategoryInfo(addPointCatIdx);
		var addPointLay = addPointCat.layers[addPointLayIdx];
		
		// Completa informazioni 
		layTocInfo.parentcategorychecked = addPointCat.checked;
		layTocInfo.layId = Math.random();
		layTocInfo.isEnabled = function(){
			if (this.parentcategorychecked){
				return this.parentcategorychecked && this.checked; 
			}else{
				return this.checked;
			}
		}
					
		//var layer = this.tocInfo.getCategoryPresetInfo(catIdx).layerList[layIdx];
					
		//var smin = (layer) ? layer.scalaMinima : -1;
    	//var smax = (layer) ? layer.scalaMassima : -1;
				
		//lay.visible=this.layerIsVisibleAtScale(scale, smin, smax, lay.minScaleMin, lay.maxScaleMax );

		// Assegna un codTPN
		var newLocalCodTPN = this.getNewLocalCodTPN();
		paramsInfo.codTPN = newLocalCodTPN;
		layTocInfo.codTPN = newLocalCodTPN;
		
		// Setto flag che indica che è un layer utente
		paramsInfo.isUserLayer = true;
		layTocInfo.isUserLayer = true;

		// TODO Gestisce solo mappa 0
		var nMappa = 0;
		
		// Verifica se il server è già definito, e se non è definito lo definisce
		var serverID = this.paramsJS.addServer(nMappa, serverInfo);
		
		// Associa il layer con il serverID corretto
		layTocInfo.serverID = serverID;
		paramsInfo.serverID = serverID;
		
		this.paramsJS.addLayer(nMappa, paramsInfo, addPointCatIdx, addPointLayIdx, bBefore);
		// Aggiorna la struttura tocInfo associata a questa legenda
		this.tocInfo.addLayer(layTocInfo, addPointCatIdx, addPointLayIdx, bBefore);
		// Invoca il metodo che consente ad una legenda che estende questa di aggiornarsi con il nuovo layer 
		this.addLayerExtend(paramsInfo, layTocInfo, serverInfo, addPointCat, addPointLay, bBefore);
		
		// Se c'è un ordine diverso da quello iniziale lo ricrea da zero
		if (this.tocInfo.layerOrder && this.tocInfo.layerOrder.length>0) this.tocInfo.layerOrder = this.createOrRefreshLayerOrder();

		this.fireEvent('layerAdded', this.tocInfo, paramsInfo, layTocInfo, serverInfo);

		// Se il server non è disponibile. Deve essere fatto dopo aver lanciato l'evento per fare in modo che tutto sia aggiornato 
		if (layTocInfo.temporaryNotAvailable) {
			this.setLayerStateChange(layTocInfo.catIdx, layTocInfo.layIdx, false, true);	
		}
		
	},
	
	/**
	 * @method addLayerExtend
	 * Metodo astratto da estendere per gestire a livello di singola tipologia di legenda l'aggiunta della categoria per esempio nella GUI.
	 * 	 
	 * @param {Object} paramsInfo
	 * Info relative al layer da inserire in paramsJS
	 * 
	 * @param {Object} layTocInfo
	 * Tocinfo del layer da aggiungere
	 * 
	 * @param {Object} serverInfo
	 * Info sul server del layer da inserire	 * @param {Object} addPointCat Punto di inserimento (Categoria) 
	 * 
	 * @param {Object} addPointLay
	 * Punto di inserimento (Layer)
	 * 
	 * @param {Object} bBefore
	 * indica se aggiungere prima o dopo
	 * 
	 */
	addLayerExtend: function(paramsInfo, layTocInfo, serverInfo, addPointCat, addPointLay, bBefore) {
	
	},
	
	/**
	 * @method onTOCInfoCatTreeIdxUpdate
	 * Metodo invocato al cambio dell'indice di categoria su tocInfo. I diversi tipi di legenda devono implementarlo per gestire l'aggiornamento sulla GUI della legenda
	 * 
	 * @param {Object} catId
	 * Id della categoria
	 * 
	 * @param {Object} oldCatTreeIdx
	 * indice che è stato cambiato
	 * 
	 * @param {Object} newCatTreeIdx
	 * nuovo valore dell'indice
	 * 
	 */
	onTOCInfoCatTreeIdxUpdate: function(catId, oldCatTreeIdx, newCatTreeIdx) {
		
	},
	
	/**
	 * @method
	 * Metodo invocato al cambio dell'indice di layer su tocInfo. I diversi tipi di legenda devono implementarlo per gestire l'aggiornamento sulla GUI della legenda
	 * 
	 * @param {Object} oldCatTreeIdx
	 * vecchio indice categoria
	 * 
	 * @param {Object} oldLayTreeIdx
	 * indice layer che è stato cambiato
	 * 
	 * @param {Object} newCatTreeIdx
	 * nuovo indice categoria
	 * 
	 * @param {Object} newLayTreeIdx
	 * nuovo valore dell'indice di layer
	 * 
	 */
	onTOCInfoLayIdxUpdate: function(layId, catTreeIdx, oldLayTreeIdx, newCatTreeIdx, newLayTreeIdx) {
		
	},
		
	/** 
	 * @method getNewLocalCodTPN
	 * Genera un nuovo codTPN local
	 * 
	 * @return {Object}
	 * il nuovo codTPN locale
	 * 
	 */
	getNewLocalCodTPN: function() {
		
		this.lastUsedLocalCodTPN = (this.lastUsedLocalCodTPN) ? this.lastUsedLocalCodTPN + 1 : this.paramsJS.codTPNClientLayerBase + 1; //this.LOCALCODTPNBASE;
		
		return this.lastUsedLocalCodTPN; 
	
	},
	
	/**
	 * @method createOrRefreshLayerOrder
	 * Crea o ricrea la struttura layerOrder
	 * 
	 * @return {Object}
	 * restituisce la struttura layerOrder
	 * 
	 */
	createOrRefreshLayerOrder: function() {
		return this.createOrRefreshLayerOrderExtend();	
	},
	
	/**
	 * @method createOrRefreshLayerOrderExtend
	 * Metodo invocato per ricreare la struttura layerOrder,  I diversi tipi di legenda devono implementarlo per gestire la possibilità di scambiare l'ordine dei layer.
	 * 
	 * @returns {Object}
	 * deve ritornare 
	 * 
	 */
	createOrRefreshLayerOrderExtend: function() {
		
	},
	
	/**
	 * @method getUserWMSList
	 * restituisce un array di oggetti  che identificano i layer inseriti dall'utente (non presenti nel preset originale)
	 * 
	 * @return {Array}
	 * array di oggetti di questo tipo { catTreeIdx: '0/1', layTreeIdx: '0'}
	 * 
	 */
	getUserWMSList: function() {
	
		var userWMSList = [];		

		if (this.tocInfo.layerOrder && this.tocInfo.layerOrder.length>0) {
			
			for (var i = 0; i < this.tocInfo.layerOrder.length; i++) {
				var laypos = this.tocInfo.layerOrder[i];
				var cat = this.tocInfo.getCategoryInfo(laypos.cat);
				var lay = cat.layers[laypos.lay];
				if (lay.isUserLayer) {
					userWMSList.push({catTreeIdx: lay.catTreeIdx, layTreeIdx: lay.layTreeIdx});
				}
			}
		} else {
		
			this.tocInfo.onEachLayer(
				function(cat, lay, catIdx, layIdx) {
					if (lay.isUserLayer) {
						userWMSList.push({catTreeIdx: catIdx, layTreeIdx: layIdx});
					}
				}, this
			);

		}
		return userWMSList;
	},
	
	/**
	 * @method getVisibleUserWMSList
	 * Restituisce un array di oggetti  che identificano i layer inseriti dall'utente (non presenti nel preset originale) e che sono visibili (checked e visible)
	 * 
	 * @return {Array}
	 * array di oggetti di questo tipo { catTreeIdx: '0/1', layTreeIdx: '0'}
	 * 
	 */
	getVisibleUserWMSList: function() {
	
		var userWMSList = this.getUserWMSList();
		var retVal = [];
		for (var i = 0; i < userWMSList.length; i++) {
			var idxObj = userWMSList[i]; 
			var currCat = this.tocInfo.getCategoryInfo(idxObj.catTreeIdx);
			var currLayer =  currCat.layers[idxObj.layTreeIdx];	
			
			if ( this.tocInfo.areAllParentCatChecked(currLayer.catTreeIdx) && currCat.checked && currLayer.checked && currLayer.visible ){
				retVal.push({catTreeIdx: idxObj.catTreeIdx, layTreeIdx: idxObj.layTreeIdx});
			}
		}	
		return retVal;
	},
	
	
	/**
	 * @method saveToCommand
	 * Serializza lo stato della legenda in un comando toloCommand.tocCheck
	 * 
	 */
	saveToCommand: function() {
		
		var cmd = Ext.create('TolomeoExt.ToloCommand.tocCheck', {
								mode: 'uncheckOthers',
								ver: 3
				});
		
		this.tocInfo.onEachLayer(
				function(cat, lay, catIdx, layIdx) { 
					
					if (this.tocInfo.areAllParentCatChecked(catIdx)) {
						if (lay.itemType=='layer' && cat.checked && lay.checked && lay.hidden==false ) {
							var s = (lay.serverID=="") ?  "INLINESERVERID" : lay.serverID;
							cmd.addTocEntry(s, lay.name, true, lay.opacity, (lay.styleCapable?lay.style:false));
						} else {
							if (lay.itemType=='text') {
								cmd.addTocTextEntry(lay.descr);
							}
						} 
					}
					/*
					if (this.tocInfo.areAllParentCatChecked(catIdx) && cat.checked && lay.checked && lay.hidden==false && lay.itemType=='layer') {
						var s = (lay.serverID=="") ?  "INLINESERVERID" : lay.serverID;
						cmd.addTocEntry(s, lay.name, true, lay.opacity);	
					} */
					
				},
				this
			);
		
		return cmd;
	},
	
	enableJ2QFeatures: function(){
		this.j2qConnected = true;
	},
	
	updateCustomQuery: function(cq) {
		this.customQuery = cq;
	},
	
	onCategoryExpand: function(catIdx){
		if (this.tocInfo) {
			this.tocInfo.getCategoryInfo(catIdx).expanded=true;
		}
		this.fireEvent('categoryExpand', this.tocInfo, catIdx);
	},
	
	onCategoryCollapse: function(catIdx){
		if (this.tocInfo) {
			this.tocInfo.getCategoryInfo(catIdx).expanded=false;
		}
		this.fireEvent('categoryCollapse', this.tocInfo, catIdx);
	},
	
	onLayerExpand: function(catIdx, layIdx){
		if (this.tocInfo) {
			this.tocInfo.getCategoryInfo(catIdx).layers[layIdx].expanded=true;
		}
		this.fireEvent('layerExpand', this.tocInfo, catIdx, layIdx);
	},
	
	onLayerCollapse: function(catIdx, layIdx){
		if (this.tocInfo) {
			this.tocInfo.getCategoryInfo(catIdx).layers[layIdx].expanded=false;
		}
		this.fireEvent('layerCollapse', this.tocInfo, catIdx, layIdx);
	}
	
	
	/*,
	
	getLegendaInfo: function(posObj, scale) {
		var retVal = {};
		retVal.layers = [];
		
		var vl = this.getVisibleLayers();
		
		for (var i=0; i < vl.length; i++) {
			var li = {};
			var l = vl[i];
			li.nome = l.descr;
			// Aggiunge le classi
			li.classi = [];
			for (j=0; j < l.classi; j++) {
				var voceLegenda = this.createVoceLegenda(
									l.classi[j], 
									l);
				li.classi.push();
			}
			// Aggiunge le info per il layer corrente
			retVal.layers.push(li);
		}
		return retVal;
	}
	
	createVoceLegenda: function(classe, layer, posObj, scale) {
		var retVal = {};
		
		var src = classe.nome;
		var paramScala = "";
		var paramPos = "";
		var stile = (layer.style && layer.style!="") ? layer.style : "default";
		
		if (classe.tipoNome==1) {
			// Se legenda dipendente da scala
			if ( scale && layer.stiliIndipDaScala!=undefined && layer.stiliIndipDaScala==false && (classe.nomeParamScala) && (classe.nomeParamScala!="")) {
				paramScala = classe.nomeParamScala + "=" + scale;
				src += ((src.indexOf("?")!=-1) ? "&" : "?") + paramScala;
			}
			if (posObj && layer.stiliIndipDaPosizione!=undefined && layer.stiliIndipDaPosizione==false) {
				paramPos += "SRS=" + posObj.srid;
				paramPos += "&BBOX=" + posObj.bbox.left  
									+ ',' + posObj.bbox.bottom
									+ ',' + posObj.bbox.right
									+ ',' + posObj.bbox.top;
				paramPos += "&WIDTH="  + posObj.width;
				paramPos += "&HEIGHT=" + posObj.height;
				src += ((src.indexOf("?")!=-1) ? "&" : "?") + paramPos;
			}
			retVal.nomevoce = "";
			retVal.url = src;
		} else {
			retVal.nomevoce = classe.nome;
			retVal.url = classe.icoUrl;
		}
		
		return retVal;
	}
	*/
	
});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloTreeTOCPanelExt
 * 
 * 
 */
Ext.define('TolomeoExt.ToloTreeTOCPanelExt', {

	extend: 'TolomeoExt.ToloTOCPanelExt',
	
	alias: 'widget.tx_toloTreeTOCPanelExt',
	
	//requires: [],
 	
	/** 
	 * @property {Object} tree
	 * 
	 * 
	 */
	tree: null,

	/** 
	 * @property {Object} treeRootNode
	 * 
	 * 
	 */
	treeRootNode: null,
		 
	/** 
	 * @property {Object} treeColumn
	 * 
	 * 
	 */
	treeColumn: null,
	
	/** 
	 * @property {Object} filterVal
	 * 
	 * 
	 */
	filterVal: null,
	
	/** 
	 * @property {Object} waitMsgBox
	 * 
	 * 
	 */
	waitMsgBox: null,
	
	/**
	 * @method initComponent
	 * Metodo relativo alla gestione Ext.
	 * 
	 */
	initComponent: function(){
        
		var me = this;
		this.layout = 'fit';
		
		//Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);	
		var thisPanel = this;
		this.tbar =[{ xtype: 'button',
						  iconCls: 'legendaBtnExpand',
						  //text: 'Apri',
						  tooltip: ToloI18n.getMsg("ToloTreeTOCPanelExt.apreTutto"),
						  listeners: { 'click': { fn: this.expandNodes,
							  						
							  				   scope: this}
						  			}
					},
					{ xtype: 'button',
								  iconCls: 'legendaBtnCollapse',
					  //text: 'Chiudi',
					  tooltip: ToloI18n.getMsg("ToloTreeTOCPanelExt.chiudeTutto"),
					  listeners: { 'click': { fn: function() { this.treeRootNode.collapseChildren(true); }, 
						  				   scope: this}
					  			}
					},
					ToloI18n.getMsg("ToloTreeTOCPanelExt.filtro"),
		            {
						xtype:'trigger',
						width: 100,
						triggerCls:'x-form-clear-trigger',
						onTriggerClick:function() {
										this.setValue('');
										thisPanel.filterClear();
										thisPanel.treeRootNode.collapseChildren(true);
								},
								enableKeyEvents:true,
								listeners:{
									keyup:{
										buffer:200,		
										fn:function(field, e) {
											if(Ext.EventObject.ESC == e.getKey()) {
												field.onTriggerClick();
											} else {
												var val = this.getRawValue();
												me.filterVal = val;
												thisPanel.filterClear();
												thisPanel.filterTree(val);
												
											}
										}
									}
								}
		            }];
		
		this.callParent();
		
		var mnuItems = [];
		if (this.paramsJS.layOut.conExportQGIS) {
			mnuItems.push(this.getExportMenuItem(null, null));
		}				
				
		var model =  Ext.define('User', {
		     extend: 'Ext.data.Model',
		     fields: [
		              {name: 'disabled', type: 'boolean', useNull: true, defaultValue: null },
		              {name: 'text', type: 'string', useNull: true, defaultValue: null},
		              {name: 'hidden', type: 'boolean', useNull: true, defaultValue: null},
		              {name: 'lay', type: 'string', useNull: true, defaultValue: null},
		              {name: 'cat', type: 'string', useNull: true, defaultValue: null},
		              {name: 'classi', type: 'string', useNull: true, defaultValue: null},
		              {name: 'catId', type: 'string', useNull: true, defaultValue: null},
		              {name: 'layId', type: 'string', useNull: true, defaultValue: null},
		              {name: 'temporaryNotAvailable', type: 'boolean', useNull: true, defaultValue: null},
		              {name: 'codTPN', type: 'string', useNull: true, defaultValue: null},
		              {name: 'withOpacitySettings', type: 'boolean', useNull: true, defaultValue: null},
		              {name: 'ownerTOC', type: 'auto', useNull: true, defaultValue: null},
		              {name: 'style', type: 'string', useNull: true, defaultValue: null},
		              {name: 'itemType', type: 'string', useNull: true, defaultValue: null},
		              //{name: 'icon', type: 'string', useNull: true, defaultValue: null},
		              // Campi utilizzati via codice js per modifica visualizzazione nodo
		              {name: 'nodeFiltered', type: 'boolean', useNull: true, defaultValue: false},				// True se il nodo è filtrato da funzione di ricerca (non risponde a criterio di ricerca 
		              {name: 'nodeVisibleAtScale', type: 'boolean', useNull: true, defaultValue: true},			// True se il nodo visibile alla scala attuale
		              {name: 'nodeWithUnfilteredChild', type: 'boolean', useNull: true, defaultValue: false}	// True se il nodo ha almeno un figlio non filtrato 
		     ]
		 });


		this.treestore = Ext.create('Ext.data.TreeStore', {
			proxy: {
				type: 'memory'
			},
		    root: {
		        expanded: true, 
		        text: 'root nascosta'//,
		    }, 
		    data: [],
		    autoSync: true,
		    autoLoad: false,
		    model: model
		});        
		
		this.treeRootNode = this.treestore.getRootNode();

		this.treeColumn = Ext.create('TolomeoExt.ToloTOCNodeColumnExt4', { 
									dataIndex:'text', 
									width    : Ext.isIE6 ? '100%' : 10000 // IE6 needs width:100%
							});

        this.tree = Ext.create('Ext.tree.TreePanel', {
        	store: this.treestore,
			useArrows: true,
		 	rootVisible: false,
		 	animate: true,
			border: false,
			autoScroll : true,
			hideHeaders: true,
			cls: Ext.baseCSSPrefix + 'autowidth-table',
			viewConfig: {
			    plugins: { ptype: 'treeviewdragdrop' }
			},
		    columns: [this.treeColumn]
		});
        var view = this.tree.getView();
        var me =  this;
        Ext.apply(view, {
            //if our function returns false, the original function is not called
            onCheckChange: Ext.Function.createInterceptor(view.onCheckChange,me.onCheckChangeInterceptor,me),
            getRowClass: Ext.Function.bind(me.getRowClass,me)
        });        

        this.tree.getView().on('checkchange', this.checkChange, this);
        this.tree.getView().on('beforedrop',this.nodedragover, this);
        this.tree.getView().on('drop', this.nodeDrop, this);
		this.tree.getView().on('itemclick', this.onItemClicked, this);
        this.tree.getView().on('rowfocus', this.onItemSelected, this);
        
        this.tree.getView().on("afteritemcollapse", function( node, index, item, eOpts ){ 
        												if (node.get("lay")==undefined || node.get("lay")==null){
        													// Nodo castegoria
        													thisPanel.onCategoryCollapse(node.get("cat"));
        												} else {
        													// Nodo layer
        													thisPanel.onLayerCollapse(node.get("cat"), node.get("lay"));
        												}
        												 
        												});
                                
        this.tree.getView().on("afteritemexpand", function( node, index, item, eOpts ){
											        	if (node.get("lay")==undefined || node.get("lay")==null){
															// Nodo castegoria
											        		thisPanel.onCategoryExpand(node.get("cat"));
														} else {
															// Nodo layer
															thisPanel.onLayerExpand(node.get("cat"), node.get("lay"));
														}
        												});
        
        this.tree.on('cellcontextmenu', this.menuShow, this);
        
        //this.add({html: "Attendere prego"});
        
        this.add(this.tree);
        
        this.on('afterrender', function() {
        	if (!this.isTOCGUICreated) {
				this.waitMsgBox = new Ext.LoadMask(this, {msg:"Attendere prego..."});
				this.waitMsgBox.show();
        	}
        }, this, {single: true})
        
    },
    
	/**
	 * @method onItemSelected
	 * 
	 * 
	 * @param {Object} record
	 * 
	 * 
	 * @param {Object} item
	 * 
	 * 
	 * @param {Object} index
	 * 
	 * 
	 */
    onItemSelected: function(record, item, index) {
    	this.callParent([record.get('cat'), record.get('lay'), record.get('classi')]);
    	
    },
    
	/**
	 * @method onItemClicked
	 * 
	 * 
	 * @param {Object} view
	 * 
	 * 
	 * @param {Object} record
	 * 
	 * 
	 * @param {Object} item
	 * 
	 * 
	 * @param {Object} index
	 * 
	 * 
	 * @param {Object} e
	 * 
	 * 
	 * @param {Object} eOpts
	 * 
	 * 
	 */
    onItemClicked: function(view, record, item, index, e, eOpts) {
    	this.callParent([record.get('cat'), record.get('lay'), record.get('classi'), e]);
    },
    
	/**
	 * @method getRowClass
	 * 
	 * 
	 * @param {Object} record
	 * 
	 * 
	 * @param {Object} index
	 * 
	 * 
	 * @param {Object} rowParams
	 * 
	 * 
	 * @param {Object} ds
	 * 
	 * 
	 */
	getRowClass: function(record,index,rowParams,ds){
	
    	var cls = '';
    	
		if (record.get('hidden')) cls+=' tocitemhidden ';
		if (!record.get('nodeVisibleAtScale')) cls+=' tocitemnotvisible ';
		if (!record.get('nodeWithUnfilteredChild') && record.get('nodeFiltered')) cls+=' tocitemfiltered ';
		if (record.get('disabled')) cls+=' tree-node-disabled ';
		if (record.get("itemType")=='separator') {
			cls += " legendaSeparatorRow ";
		}
    	
	    return cls;
	},    

	/**
	 * @method onCheckChangeInterceptor
	 * Consente di impedire il cambio di check state nel caso sia disabilitato
	 * 
	 * @param {Object} record
	 * 
	 * 
	 */
    onCheckChangeInterceptor: function(record) {
    	if (record.get('disabled')){
            return false;
        } 
    },

	/**
	 * @method expandNodes
	 * 
	 * 
	 */
    expandNodes: function() {
    	Ext.suspendLayouts();
		this.treeRootNode.cascadeBy(function(nd) {
				if (nd.get('lay')==null) {
					nd.expand(false, false);
				}});
		Ext.resumeLayouts(true);
	},

	/**
	 * @method filterTree
	 * 
	 * 
	 * @param {Object} val
	 * 
	 * 
	 */
    filterTree: function(val) {
    	Ext.suspendLayouts();

    	var re = new RegExp('.*' + val + '.*', 'i');
		this.treeRootNode.cascadeBy(
    		function(n) {
    			if (n.get('classi')!=null) return false; // se stiamo esaminando il nodo finale (legenda) smettere per non farlo partecipare alla ricerca
    			if (!n.get('hidden')) {
	    			if (re.test(n.get('text')) ) {
	    				this.setNodeFiltered(n, false);
	    				return true;
	    			} else {
	    				if (n!== this.treeRootNode)	this.setNodeFiltered(n, true);
	    				return true;  // continuo ad attraversare l'albero perchè se qualche figlio è attivo va attivato anche questo nodo
	    			}
    			}
    		}, this
    	);
		
		Ext.resumeLayouts(true);
		
		this.expandNodes();
		    	
    },
    
	/**
	 * @method setNodeFiltered
	 * 
	 * 
	 * @param {Object} node
	 * 
	 * 
	 * @param {Object} dafiltrare
	 * 
	 * 
	 */
    setNodeFiltered: function(node, dafiltrare) {
        
        node.set('nodeFiltered', dafiltrare);
        	
        // Aggiorna flag nodeWithUnfilteredChild in tutta la gerarchia a salire
       	var p = node.parentNode;
       	var bContinua = true;
        while(p && bContinua) {
        	
        	// controllo tutti i figli p.get('nodeWithUnfilteredChild')
        	var withUnfiltered = false;
        	for (var i = 0; i< p.childNodes.length ; i++) {
        		if (p.childNodes[i].get('classi')==null && p.childNodes[i].get('hidden')==false && (!p.childNodes[i].get('nodeFiltered') || p.childNodes[i].get('nodeWithUnfilteredChild') )) { 
        			withUnfiltered=true;
        			break;
        		}
        	}
        	
        	if (p.get('nodeWithUnfilteredChild')!= withUnfiltered ) {
        		p.set('nodeWithUnfilteredChild', withUnfiltered);
        	} else {
        		bContinua=false;
        	}
        		
        	p = p.parentNode;
		}        	
        
    },    

	/**
	 * @method filterClear
	 * 
	 * 
	 */
    filterClear: function() {
    	Ext.suspendLayouts();
    	this.treeRootNode.cascadeBy(
        		function(n) {
        				if (!n.get('hidden')) {
        					n.set('nodeWithUnfilteredChild', false);
        					n.set('nodeFiltered', false);
   	                     }
        				
        		}, this
        	);
    	Ext.resumeLayouts(true);
    },
    
	/**
	 * @method menuShow
	 * 
	 * 
	 * @param {Object} view
	 * 
	 * 
	 * @param {Object} td
	 * 
	 * 
	 * @param {Object} cellIndex
	 * 
	 * 
	 * @param {Object} record
	 * 
	 * 
	 * @param {Object} tr
	 * 
	 * 
	 * @param {Object} rowIndex
	 * 
	 * 
	 * @param {Object} e
	 * 
	 * 
	 * @param {Object} eOpts
	 * 
	 * 
	 */
	menuShow : function( view, td, cellIndex, record, tr, rowIndex, e, eOpts ){
    	
		var menu = this.getContextMenu(record.get('cat'), record.get('lay'));
		if (menu) {
    		menu.showAt(e.getXY()); //node.ui.getAnchor()
    		
		}
		e.preventDefault();
   },
    
	/**
	 * @method nodedragover
	 * 
	 * 
	 * @param {Object} node
	 * 
	 * 
	 * @param {Object} data
	 * 
	 * 
	 * @param {Object} overModel
	 * 
	 * 
	 * @param {Object} dropPosition
	 * 
	 * 
	 * @param {Object} dropHandlers
	 * 
	 * 
	 * @param {Object} eOpts
	 * 
	 * 
	 */
    nodedragover: function(node, data, overModel, dropPosition, dropHandlers, eOpts ) { //dropEvent
    	if (dropPosition == 'append')  
    		return false;
    	
    	if(overModel.parentNode.id!=data.records[0].parentNode.id)
    		return false;
    	
    },
    
	/**
	 * @method nodeDrop
	 * 
	 * 
	 * @param {Object} node
	 * 
	 * 
	 * @param {Object} data
	 * 
	 * 
	 * @param {Object} overModel
	 * 
	 * 
	 * @param {Object} dropPosition
	 * 
	 * 
	 * @param {Object} eOpts
	 * 
	 * 
	 */
    nodeDrop: function( node, data, overModel, dropPosition, eOpts ) { 
    	// Andrebbe fatto in modo da garantirsi che l'albero venga percorso nell'ordine giusto
    	this.tocInfo.layerOrder = this.createOrRefreshLayerOrder();
    	this.layerOrderChange();
    	
    },
    
	/**
	 * @method createOrRefreshLayerOrderExtend
	 * 
	 * 
	 */
    createOrRefreshLayerOrderExtend: function() {
    	// Andrebbe fatto in modo da garantirsi che l'albero venga percorso nell'ordine giusto
    	var layerOrder = [];
    	this.treeRootNode.cascadeBy(
			function(nd) {
				if ( nd.get('classi')==null && nd.get('lay')!=null) {
					layerOrder.push({cat: nd.get('cat'), lay: nd.get('lay')});
				}
				return true;
			},
			this
		);
    	
		return layerOrder;
    },
    
    /**
     * @method checkChange
     * 
     * 
     * @param {Object} node
     * node.
     * 
     * @param {Object} checked
     * checked.
     * 
     */
    checkChange: function( node, checked ) {
    	
    	var cat = node.get('cat');
    	var lay = node.get('lay');
    	
    	// Se il click e' su una categoria vengono disabilitati o abilitati tutti i layer della categoria stessa
    	if (lay==null) {
    		this.setCategoryStateChange(cat, checked);
    		
    	} else {
    		this.setLayerStateChange(cat,lay, checked);
    	}    	
    	
    },
    
  /**
	 * @method setLayerStateChange
	 * Aggiorna lo stato di un layer a livello di treePanel quando viene notificata
	 * una modifica dalla classe padre.
	 * 
	 * @param {Object} cat
	 * 
	 * 
	 * @param {Number} lay
	 * layer della tocInfo
	 * 
	 * @param {Object} checked
	 * 
	 * 
	 */
	setLayerStateChange : function(cat, lay, checked) {
		 this.callParent(arguments);
		if (this.tocInfo != null && lay != null) {
			var layer = this.tocInfo.getCategoryInfo(cat).layers[lay];
			var layerNode = this.treeRootNode.findChild('layId',layer.layId,true);
			
			if( layer.userSwitchable &&   (layerNode.get('checked') != layer.checked)){
				layerNode.set('checked', layer.checked);
			}	
		}		
	},

  /**
	 * @method _createCategory
	 * @private
	 * Aggiorna lo stato di un layer a livello di treePanel quando viene notificata
	 * una modifica dalla classe padre.
	 * 
	 * @param {Object} cat
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} addPointCatId
	 * 
	 * 
	 * @param {Object} before
	 * 
	 * 
	 */
    _createCategory: function(cat, catIdx, addPointCatId, before) {

    	var bConIcone = this.getParametriMappaCurr().legenda.conIcone;

    	var nodeCfg = {
    	   			text: cat.catDescr,
					hidden: cat.hidden,
					lay: null,
					cat: catIdx,
					classi: null,
					catId: cat.catId,
					allowDrag: this.tocInfo.orderChangeCapable,
					checked: (cat.userSwitchable) ? cat.checked : undefined,
					disabled: !this.tocInfo.areAllParentCatChecked(catIdx),
					href:  (cat.clickUrl) ? "#" : null, //this.calcolaCategoryClickUrl(cat),
					hrefTarget: (cat.clickTarget) ? cat.clickTarget : undefined,
					url: null,
					cls: 'bold' ,
					iconCls: bConIcone ? "iconLegendaCategoria" : 'treenode-no-icon',
					expanded: cat.expanded,
					qtip: this.calcolaCatToolTip(catIdx),
					itemType: cat.itemType					
				}; 
				
		if (cat.itemType && cat.itemType=='text' && cat.itemIcon) {
			var serverIco = "";
			if (cat.itemIcon.indexOf("http://")==-1 && cat.itemIcon.indexOf("http://")==-1) {
    			serverIco = this.TOLOMEOServer + this.TOLOMEOContext + "/";
			}
    		nodeCfg.icon = serverIco+cat.itemIcon;
			nodeCfg.iconCls = 'iconClassToc';
			
    	}			
		
		var parentCatIdx = this.tocInfo.getParentCategoryIdx(catIdx);
		var parentNode = (parentCatIdx=="") ? this.treeRootNode : this.treeRootNode.findChild('cat', parentCatIdx, true)  ;    //this.findChildNodeByAttribute(this.treeRootNode, 'cat', parentCatIdx)
		var nodeI = null;
		
		if (addPointCatId) {
			var nodeAddPoint = this.treeRootNode.findChild('catId', addPointCatId, true);
			
			if (before) {
				nodeI = parentNode.insertBefore(nodeCfg, nodeAddPoint);	
			} else {
				var nodeAfter = null;
				// Cerca la posizione di nodeAddPoint
				for (var i=0; i < parentNode.childNodes.length; i++) {
						var n = parentNode.getChildAt(i);
						if (n==nodeAddPoint) {
							if (i < parentNode.childNodes.length -1) {
								nodeAfter = parentNode.getChildAt(i+1);
							}
							break;
						}
				}
				if (nodeAfter) {
					// non è l'ultimo
						nodeI = parentNode.insertBefore(nodeCfg, nodeAfter);	
				} else {
						nodeI = parentNode.appendChild(nodeCfg);	
			 
				}
			}
			
		} else {
			// Cerco il primo nodo layer all'interno di parentNode
			var idxFirstLay = null;
			for (var i =0; i<parentNode.childNodes.length; i++) {
				if (parentNode.childNodes[i].get('lay')!=null) {
					idxFirstLay = i;
					break;
				}
			}
			if (idxFirstLay!=null) {
				nodeI = parentNode.insertBefore(nodeCfg, parentNode.childNodes[idxFirstLay]);	
			} else {
				nodeI = parentNode.appendChild(nodeCfg);
			}
		}
		

		
		this.setNodeLayerVisibility(nodeI, true);
		
		/*nodeI.on("click", 
			function(nd) {
				this.fireEvent('categoryLinkClick', nd.get('cat')); 
			}, 
			this);
		*/
		
		// Aggiunta Layer
		this.tocInfo.onEachLayer(
				function(cat, lay, catIdx, layIdx) { this._createLayer(cat, lay, catIdx, layIdx, nodeI) },
				this,
				catIdx,
				false
		);
		
		if(cat.expanded){
			this.expandCategories(catIdx);
		/*	this.tocInfo.onEachParentCategory(
					function(parentCat, parentCatIdx) {
						if (!parentCat.expanded) {
							var parentNode = (parentCatIdx=="") ? this.treeRootNode : this.treeRootNode.findChild('cat', parentCatIdx, true); // this.findChildNodeByAttribute(this.treeRootNode, 'cat', parentCatIdx) 
								
							
							if(!parentNode.isExpanded()){
								parentNode.expand();
							}
						}
					}, 
					this,
					catIdx
			)*/
		}
		
    },
    
    /**
     * @method expandCategories
     * Espande tutte le categorie fino a quella rappresentata dacatIdx
     * 
     * @param {Number} catIdx
     * 
     * 
     */
    expandCategories: function(catIdx) {
    	Ext.suspendLayouts();
    	
    	var thisNode = this.treeRootNode.findChild('cat', catIdx, true);;
		if(!thisNode.isExpanded()){
			thisNode.expand();
		}
    	
		this.tocInfo.onEachParentCategory(
				function(parentCat, parentCatIdx) {
					if (!parentCat.expanded) {
						var parentNode = (parentCatIdx=="") ? this.treeRootNode : this.treeRootNode.findChild('cat', parentCatIdx, true); // this.findChildNodeByAttribute(this.treeRootNode, 'cat', parentCatIdx) 
						
						if(!parentNode.isExpanded()){
							parentNode.expand();
						}
					}
				}, 
				this,
				catIdx
		);
		Ext.resumeLayouts(true);
		
    },
    
    /**
     * @method _layToolTipCfg
     * @private
     * Espande tutte le categorie fino a quella rappresentata dacatIdx
     * 
     * @param {Object} lay
     * 
     * 
     */
    _layToolTipCfg: function(lay) {
    	
    	var layToolTipCfgTxt = this.calcolaLayToolTip(lay.catTreeIdx, lay.layTreeIdx);
    	layToolTipCfgTxt = (layToolTipCfgTxt) ? layToolTipCfgTxt : undefined;
    	
    	return lay.temporaryNotAvailable ? ToloI18n.getMsg("ToloTreeTOCPanelExt.layerNonDisp") : layToolTipCfgTxt;
    },
        
    /**
     * @method _createLayer
     * @private
     * 
     * 
     * @param {Object} cat
     * 
     * 
     * @param {Object} lay
     * 
     * 
     * @param {Object} catIdx
     * 
     * 
     * @param {Object} layIdx
     * 
     * 
     * @param {Object} nodeI
     * 
     * 
     * @param {Object} addPointCatId
     * 
     * 
     * @param {Object} addPointLayId
     * 
     * 
     * @param {Object} bBefore
     * 
     * 
     */
    _createLayer: function(cat, lay, catIdx, layIdx, nodeI, addPointCatId, addPointLayId, bBefore) {
    	
    	var bConIcone = this.getParametriMappaCurr().legenda.conIcone;

    	var iconClsObj=this.calcolaIconCls(catIdx, layIdx);
    	var iconCls = iconClsObj.iconCls;
    	bConIcone = bConIcone || iconCls.forzaConIcone;
    	var singleClass = this.getParametriMappaCurr().legenda.singleClass;
    	
    	
    	var me = this;
    	
    	var node1Cfg = {
    	    			text: lay.descr,
    	    			hidden: lay.hidden, 
						lay: layIdx,
						cat: catIdx,
						classi: null,
						layId: lay.layId,
						codTPN: lay.codTPN,
						withOpacitySettings: lay.withOpacitySettings,
						ownerTOC: this,				
						style: lay.style,
						allowDrag: this.tocInfo.orderChangeCapable,
						temporaryNotAvailable: lay.temporaryNotAvailable,
						checked: (lay.userSwitchable) ? lay.checked : undefined, 
						disabled: !(this.tocInfo.areAllParentCatChecked(catIdx) && cat.checked), //!cat.checked,
						
						iconCls: bConIcone ? iconCls : 'treenode-no-icon',
						qtip: this._layToolTipCfg(lay),   // utilizzo qtip e non qtipCfg altrimenti non riesco a cambiarlo in seguito con setTooltip
						href: (lay.clickUrl) ? "#" : null, // this.calcolaLayerClickUrl(lay),
						hrefTarget: (lay.clickTarget) ? lay.clickTarget : undefined,
						expanded: lay.expanded,
						itemType: lay.itemType
				};
		
		if (lay.itemType && lay.itemType=='text' && lay.itemIcon) {
			var serverIco = "";
			if (lay.itemIcon.indexOf("http://")==-1 && lay.itemIcon.indexOf("http://")==-1) {
    			serverIco = this.TOLOMEOServer + this.TOLOMEOContext + "/";
			}
    		node1Cfg.icon = serverIco+lay.itemIcon;
			node1Cfg.iconCls = 'iconClassToc';
			
    	}				
				
		var nodeJ = null;
  
		
		// se è richiesta la singola classe si mette l'icona a livello del layer
		if(singleClass){
			var paramScala = "";
			if ( this.scale && lay.stiliIndipDaScala==false && (lay.classi[0].nomeParamScala) && (lay.classi[0].nomeParamScala!="")) {
				paramScala = ((lay.classi[0].nome && lay.classi[0].nome.indexOf("?")!=-1) ? "&" : "?") +  lay.classi[0].nomeParamScala + "=" + this.scale;
			}
			
			var url = lay.classi[0].nome;
			var pat = /width\=\d+/;
			url = url.replace(pat, "");
			var pat = /height\=\d+/;
			url = url.replace(pat, "");
			var pat = /\&\&/;
			url = url.replace(pat, "&");
			
			node1Cfg.icon = url + paramScala;
		}
		
  
		if (addPointLayId) {
			
			var nodeAddPointCat = nodeI;
			//var nodeAddPointCat = this.treeRootNode.findChild('catId', addPointCatId, true);
			var addNodeLay = null;
			
			// Cerca la posizione di nodeAddPoint
			for (var i=0; i < nodeAddPointCat.childNodes.length; i++) {
				var n = nodeAddPointCat.getChildAt(i);
				if (n.get('layId')==addPointLayId) {
					if (bBefore) {
						addNodeLay = n;
					} else {
						if (i < nodeAddPointCat.childNodes.length -1) {
							addNodeLay = nodeAddPointCat.getChildAt(i+1);
						}
					}
					break;
				}
			}
			
			if (addNodeLay) {
				nodeJ = nodeI.insertBefore(node1Cfg, addNodeLay);	
			} else {
				nodeJ = nodeI.appendChild(node1Cfg, addNodeLay);
			}
		} else {
			nodeJ = nodeI.appendChild(node1Cfg);
		}
				
	/*	nodeJ.on("click", 
					function(nd) {
						this.fireEvent('layerLinkClick', nd.get('cat'), nd.get('lay')); 
					}, 
					this);
		*/		
		this.setNodeLayerVisibility(nodeJ, lay.visible); 
		
		if(lay.expanded){
			
			if(catIdx && nodeI){

				this.tocInfo.onEachParentCategory(
						function(parentCat, parentCatIdx) {
							if (!parentCat.expanded) {
								var parentNode = (parentCatIdx=="") ? this.treeRootNode : this.treeRootNode.findChild('cat', parentCatIdx, true);

								if(!parentNode.isExpanded()){
									parentNode.expand();
								}
							}
						}, 
						this,
						catIdx
				)
				
				if(!nodeI.isExpanded()){					
					nodeI.expand();
				}
				
							
			}						
		}
		
		// Aggiunta Classi
		// sse non è singola classe
		if( ! singleClass ){
		for (var k=0; k<lay.classi.length; k++) {
			var definedStyles = lay.definedStyles;
			var node2Opts = {	text: this._createTagVoceLegenda(lay.classi[k], lay), 
								lay: layIdx,
								cat: catIdx,
								classi: k,
								allowDrag: false,
								leaf:true
							} ;
			

			if (lay.classi[k].icoUrl!=null && lay.classi[k].icoUrl!="") {
				node2Opts.icon = this.TOLOMEOServer + lay.classi[k].icoUrl;
				node2Opts.iconCls = 'iconClassToc';
			} else {
				node2Opts.iconCls = 'treenode-no-icon';
			}; 
    		var nodeK = nodeJ.appendChild(node2Opts);
		}
		}
    },
    
    /**
     * @method createTOC
     * 
     * 
     * @param {Object} scale
     * 
     * 
     */
    createTOC: function (scale) {

    	this.callParent(arguments);
		this.tocInfo.onEachCategory(
				this._createCategory,
				this
		);
		
    	this.doLayout();
    	this.isTOCGUICreated = true;
    	if (this.waitMsgBox) this.waitMsgBox.hide();
    	// Riabilita toolbar
    	var toolbar = this.getDockedItems('toolbar[dock="top"]')[0];
    	toolbar.enable();
    	
    	this.fireEvent('tocGuiCreate');
	}, 
	
	/**
	 * @method updateTOC
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 * 
	 * @returns {Boolean}
	 * 
	 * 
	 */
	updateTOC: function(scale) {		
		this.callParent(arguments);
		
		this.treeRootNode.cascadeBy(
			function(nd) {
				if (nd.get('classi')==null && nd.get('lay')!=null) {
					this.setNodeLayerVisibility(nd, this.tocInfo.getCategoryInfo(nd.get('cat')).layers[nd.get('lay')].visible);
					
				} else if (nd.get('classi')!=null) {
					// ATTENZIONE: il testo in alcuni casi contiene anche la legendGraphic
					var layer = this.tocInfo.getCategoryInfo(nd.get('cat')).layers[nd.get('lay')];
					var classe = layer.classi[nd.get('classi')];
					var t = this._createTagVoceLegenda(classe, layer); 	
					if (t!=nd.get('text')) {
						nd.set('text', t);
						var lay = this.tocInfo.getCategoryInfo(nd.get('cat')).layers[nd.get('lay')];
						nd.parentNode.set('qtip',this._layToolTipCfg(lay));
					}
				}
				return true;
			},
			this
		)		
	},
	
	updateCustomQuery: function(cq) {
		this.callParent(arguments);
		this.updateTOC();
	},
	
	/**
	 * @method _createTagVoceLegenda
	 * @private
	 * 
	 * 
	 * @param {Object} classe
	 * 
	 * 
	 * @param {Object} layer
	 * 
	 * 
	 * @param {Object} scale
	 * 
	 *
	 */
	_createTagVoceLegenda: function(classe, layer) {

		var tag =  "";
		var src = classe.nome;
		var paramScala = "";
		var paramPos = "";
		var stile = (layer.style && layer.style!="") ? layer.style : "default";
		

		if (classe.tipoNome==1) {
			// Nel caso di WMS
			
			// Se legenda dipendente da scala
			if ( this.scale && layer.stiliIndipDaScala!=undefined && layer.stiliIndipDaScala==false && (classe.nomeParamScala) && (classe.nomeParamScala!="")) {
				paramScala = classe.nomeParamScala + "=" + this.scale;
				src += ((src.indexOf("?")!=-1) ? "&" : "?") + paramScala;
			}
			if (this.posObj && layer.stiliIndipDaPosizione!=undefined && layer.stiliIndipDaPosizione==false) {
				paramPos += "SRS=" + this.posObj.srid;
				paramPos += "&BBOX=" + this.posObj.bbox.left  
									+ ',' + this.posObj.bbox.bottom
									+ ',' + this.posObj.bbox.right
									+ ',' + this.posObj.bbox.top;
				paramPos += "&WIDTH="  + this.posObj.width;
				paramPos += "&HEIGHT=" + this.posObj.height;
				src += ((src.indexOf("?")!=-1) ? "&" : "?") + paramPos;
			}
			
			if (this.customQuery!=null) {
				var paramsCustomQueryObj = {};
				// TODO supportata solo mappa 0
				var nMappa = 0;
				var cq = TolomeoExt.ToloViewerOLPanel.customQueryForServer(this.customQuery[nMappa], layer.serverID);
				Ext.apply(paramsCustomQueryObj, TolomeoExt.ToloViewerOLPanel.customQueryToGeoserverObj(cq));
				Ext.apply(paramsCustomQueryObj, TolomeoExt.ToloViewerOLPanel.customQueryToMapserverObj(cq));
				src += ((src.indexOf("?")!=-1) ? "&" : "?") + Ext.urlEncode(paramsCustomQueryObj);
			}
			
			tag =  '<img src="' + src + '" alt="' + ToloI18n.getMsg("ToloTreeTOCPanelExt.stileApplicato") + ' ' + stile + '" title="' + ToloI18n.getMsg("ToloTreeTOCPanelExt.stileApplicato") + ' '  +stile + '" />';	
		} else {
			// Nel caso di MAPSERVER cgi			
			tag = classe.nome;
		}
		
		return tag;
	},
	
	/**
	 * @method setNodeLayerVisibility
	 * 
	 * 
	 * @param {Object} node
	 * 
	 * 
	 * @param {Object} visible
	 * 
	 * 
	 */
	setNodeLayerVisibility: function(node, visible) {
    	if (visible) {
    		node.set('nodeVisibleAtScale', true);
		} else {
			node.set('nodeVisibleAtScale', false);
		}

		var iconClsObj = this.calcolaIconCls(node.get('cat'), node.get('lay'), visible);
		if (iconClsObj != null) {
			node.set('iconCls',iconClsObj.iconCls);
		}
	},	
	
	
	/**
	 * @method setCategoryStateChange
	 * Aggiorna lo stato di una categoria a livello di treePanel quando viene notificata
	 * una modifica dalla classe padre.
	 * 
	 * @param {String} cat
	 * categoria della tocInfo
	 * 
	 * @param {Object} checked
	 * 
	 * 
	 */
	setCategoryStateChange : function(cat, checked) {
		this.callParent(arguments);
		
		if (this.tocInfo != null) {
			
			var category = this.tocInfo.getCategoryInfo(cat); 
			var categoryNode = this.treeRootNode.findChild('catId', category.catId, true);
			if(category.userSwitchable && (category.checked != categoryNode.get('checked'))) {
				categoryNode.set('checked', category.checked);
			}
	
			categoryNode.cascadeBy(
	    			function(nd) {
	    				if (nd!=categoryNode) {
	    					var currCatIdx = nd.get('cat');
	    					var currCat = this.tocInfo.getCategoryInfo(currCatIdx);
	    					if ( this.tocInfo.areAllParentCatChecked(currCatIdx) && 
	    						(nd.get('lay')==null || 
	    						(nd.get('lay')!=null && currCat.checked )) 
	    					   ) {
	    							nd.set('disabled', false);	
	    						}	    					
		    				else {
			    					nd.set('disabled', true); 
		    					}
	    				}
	    			}, this 	
	    		);
		}		
	},
	
	/**
	 * @method onTOCInfoCatTreeIdxUpdate
	 * Metodo invocato al cambio dell'indice di categoria su tocInfo. I diversi tipi di legenda devono implementarlo per gestire l'aggiornamento sulla GUI della legenda
	 * 
	 * @param {Number} catId
	 * 
	 * 
	 * @param {Number} oldCatTreeIdx
	 * indice che è stato cambiato
	 * 
	 * @param {Number} newCatTreeIdx 
	 * nuovo valore dell'indice
	 * 
	 */
	onTOCInfoCatTreeIdxUpdate: function(catId, oldCatTreeIdx, newCatTreeIdx) {
		var categoryNode = this.treeRootNode.findChild('catId', catId, true);
		if (categoryNode) {
			// Se non esiste è quella nuova
			categoryNode.set('cat', newCatTreeIdx);
		}
	},
	
	/**
	 * @method onTOCInfoLayIdxUpdate
	 * Metodo invocato al cambio dell'indice di layer su tocInfo. I diversi tipi di legenda devono implementarlo per gestire l'aggiornamento sulla GUI della legenda
	 * 
	 * @param {Number} layI
	 * id assoluto del nodo all'interno dell'albero
	 * 
	 * @param {Number} catTreeIdx
	 * vecchio indice categoria
	 * 
	 * @param {Number} oldLayTreeIdx
	 * indice layer che è stato cambiato
	 * 
	 * @param {Number} newCatTreeIdx
	 * nuovo indice categoria
	 * 
	 * @param {Number} newLayTreeIdx
	 * nuovo valore dell'indice di layer
	 * 
	 */
	onTOCInfoLayIdxUpdate: function(layId, catTreeIdx, oldLayTreeIdx, newCatTreeIdx, newLayTreeIdx) {
		/*var categoryNode = this.treeRootNode.findChild('catId', catTreeIdx, true);
		var node = this.treeRootNode.findChildBy(
			function(nd){
				return (nd.get('catId')== catTreeIdx && nd.get('layId')==oldLayTreeIdx);

			}, this, true);
		
		if (categoryNode) {
			var layerNode = categoryNode.findChild('layId', layId, true);
			layerNode.set('lay', newLayTreeIdx);
			layerNode.set('cat', newCatTreeIdx);
		}*/
		
		var node = this.treeRootNode.findChild('layId', layId, true);
		if (node) {
			node.set('lay', newLayTreeIdx);
			node.set('cat', newCatTreeIdx);
			// Aggiorna anche i nodi "classi"
			for (var i=0; i<node.childNodes.length; i++) {
				var n = node.childNodes[i];
				n.set('lay', newLayTreeIdx);
				n.set('cat', newCatTreeIdx);
				n.set('classi', i);
			}
		}
		
	},
	
	/**
	 * @method addCategoryExtend
	 * 
	 * 
	 * @param {Object} catInfo
	 * 
	 * 
	 * @param {Object} addPointCat
	 * 
	 * 
	 * @param {Object} bBefore
	 * 
	 * 
	 */
	addCategoryExtend: function(catInfo, addPointCat, bBefore) {
	
		this._createCategory(catInfo.tocInfoParams, catInfo.tocInfoParams.catTreeIdx, addPointCat.catId, bBefore);
		
	},
	
	/**
	 * @method
	 * Aggiunge un layer nella posizione indicata dai parametri.
	 * 
	 * @param {Object} paramsInfo
	 * Info relative al layer da inserire in paramsJS
	 * 
	 * @param {Object} layTocInfo
	 * Tocinfo del layer da aggiungere
	 * 
	 * @param {Object} serverInfo
	 * Info sul server del layer da inserire
	 * 
	 * @param {Object} addPointCat
	 * Indice della categoria nella quale viene aggiunto il layer 
	 * 
	 * @param {Object} addPointLay
	 * Indice layer prima o dopo del quale aggiungere il nuovo layer
	 * 
	 * @param {Boolean} bBefore
	 * indica se aggiungere prima o dopo
	 * 
	 */
	addLayerExtend: function(paramsInfo, layTocInfo, serverInfo, addPointCat, addPointLay, bBefore) {
	
		var nodeAddPointCat = this.treeRootNode.findChild('catId', addPointCat.catId, true);
		this._createLayer(addPointCat, layTocInfo, layTocInfo.catTreeIdx, layTocInfo.layTreeIdx, nodeAddPointCat, addPointCat.catId, (addPointLay) ? addPointLay.layId : null, bBefore);
	
			
	}
	
});

/* 
 Tolomeo is a developing framework for visualization, editing,  

 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.define('TolomeoExt.ToloTOCNodeColumnExt4', {
    extend: 'Ext.grid.column.Column',
    alias: 'widget.tolotoccolumn',

    tdCls: Ext.baseCSSPrefix + 'grid-cell-treecolumn',

    view: null,
    
    autoLock: true,
    lockable: false,
    draggable: false,
    hideable: false,

    iconCls: Ext.baseCSSPrefix + 'tree-icon',
    checkboxCls: Ext.baseCSSPrefix + 'tree-checkbox',
    elbowCls: Ext.baseCSSPrefix + 'tree-elbow',
    expanderCls: Ext.baseCSSPrefix + 'tree-expander',
    textCls: Ext.baseCSSPrefix + 'tree-node-text',
    innerCls: Ext.baseCSSPrefix + 'grid-cell-inner-treecolumn',
    isTreeColumn: true,
    bShowLevel: false,
    
	// NOTA BENE: il link sul nodo viene messo per dargli l'aspetto, ma come href viene messo # per poterlo gestire con l'evento itemClicked emesso dalla TOC
    cellTpl: [
      //  '<tpl if="hidden!=true" />',      
        '<tpl for="lines">',
            '<img src="{parent.blankUrl}" class="<tpl if="parent.isSep">legendaSeparatorRow</tpl> {parent.childCls} {parent.elbowCls}-img ',
            '{parent.elbowCls}-<tpl if=".">line<tpl else>empty</tpl>"/>',
        '</tpl>',
        '<img src="{blankUrl}" class="<tpl if="isSep">legendaSeparatorRow</tpl> {childCls} {elbowCls}-img {elbowCls}',
            '<tpl if="isLast">-end</tpl><tpl if="expandable">-plus {expanderCls}</tpl>"/>',
        '<tpl if="checked !== null">',
            '<input type="button" role="checkbox" <tpl if="checked">aria-checked="true" </tpl>',
                'class="{childCls} {checkboxCls}<tpl if="checked"> {checkboxCls}-checked</tpl>"/>',
        '</tpl>',
        '<tpl if="isSep">',
        		'<span class="legendaSeparator"></span>',
        '<tpl else>',
        	'<img src="{blankUrl}" class="{childCls} {baseIconCls} ',
            	'{baseIconCls}-<tpl if="leaf">leaf<tpl else>parent</tpl> {iconCls}"',
            '<tpl if="icon">style="background-image:url({icon}) !important"</tpl>/>',
        	'<tpl if="href">',
	            '<a href="#"  class="{textCls} {childCls}">{value}</a>',
        	'<tpl else>',        	
            	'<span class="layerLabel {textCls} {childCls}">{debugLevelLabel}{value}</span>',
            '</tpl>',
        '</tpl>'
     //   '</tpl>'
    ],
//{debugLevelLabel}
//{href} target="{hrefTarget}"
    
    initComponent: function() {
        var me = this;

        me.origRenderer = me.renderer;
        me.origScope = me.scope || window;

        me.renderer = me.treeRenderer;
        
        me.scope = me;        

        
        me.callParent();
        
        me.on('afterrender', me.a);
    },        

    treeRenderer: function(value, metaData, record, rowIdx, colIdx, store, view){

    	var me = this,
            cls = record.get('cls'),
            renderer = me.origRenderer,
            data = record.data,
            parent = record.parentNode,
            rootVisible = view.rootVisible,
            lines = [],
            parentData;

        if (cls) {
            metaData.tdCls += ' ' + cls;
        }

        while (parent && (rootVisible || parent.data.depth > 0)) {
            parentData = parent.data;
            lines[rootVisible ? parentData.depth : parentData.depth - 1] =
                    parentData.isLast ? 0 : 1;
            parent = parent.parentNode;
        }

        var debugLevelLabel = (this.bShowLevel) ? data.cat + "-" + data.lay + "+" + data.classi : "";
        
        var el =  me.getTpl('cellTpl').apply({
        	debugLevelLabel: debugLevelLabel, 
        	cat: data.cat,
        	lay: data.lay,
        	classi: data.classi,
            record: record,
            hidden: data.hidden,
            baseIconCls: me.iconCls,
            iconCls: data.iconCls,
            icon: data.icon,
            checkboxCls: me.checkboxCls,
            checked: data.checked,
            elbowCls: me.elbowCls,
            expanderCls: me.expanderCls,
            textCls: me.textCls,
            leaf: data.leaf,
            expandable: record.isExpandable(),
            isLast: data.isLast,
            blankUrl: Ext.BLANK_IMAGE_URL,
            href: data.href,
            hrefTarget: data.hrefTarget,
            lines: lines,
            metaData: metaData,
            isSep: (data.itemType=='separator'),
            childCls: me.getChildCls ? me.getChildCls() + ' ' : '',
            value: renderer ? renderer.apply(me.origScope, arguments) : value
        }); 
        
        
        return el;
    },
   
    a: function(col, eOpts) {
    	var i=0;
    	
    },
    
    prova: function() {
    	var i=0;
    }
});


 /* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloMenuTOCPanelExt
 * @extends TolomeoExt.ToloTOCPanelExt
 * 
 * 
 */
	
Ext.define('TolomeoExt.ToloMenuTOCPanelExt', {

	extend: 'TolomeoExt.ToloTOCPanelExt',
	
	alias: 'tx_toloMenuTOCPanelExt',

	/**
	 * @property {Object} categoryButton
	 * @private
	 * 
	 * 
	 */
	categoryButton: null,	
		
	/**
	 * @method initComponent
	 * Metodo relativo alla gestione Ext.
	 *  
	 */
	initComponent: function(){
        
		//Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);	
	
		//this.layout='hbox';
		this.callParent(arguments);
        
    },
    
    /**
     * @method checkItemChange
     * 
     * 
     * @param {Object} item
     * item.
     * 
     * @param {Boolean} checked
     * checked.
     * 
     */
    checkItemChange: function(item, checked) {
    	
    	var cat = item.attributes.cat;
    	var lay = item.attributes.lay;
    	
    	this.setLayerStateChange(item.attributes.cat, item.attributes.lay, checked);
    },
    
  /**
	 * @method setLayerStateChange
	 * Aggiorna lo stato di un layer a livello di menu items quando viene notificata
	 * una modifica dalla classe padre.
	 * 
	 * @param {String} cat
	 * 
	 * 
	 * @param {Number} lay
	 * layer della tocInfo
	 * 
	 * @param {Boolean} checked
	 * 
	 * 
	 */
	setLayerStateChange : function(cat, lay, checked) {
		this.callParent(arguments);
		if (this.tocInfo != null && lay != null) {
			
			var layer = this.tocInfo.getCategoryInfo(cat).layers[lay];
			
			for (var i=0; i<this.categoryButton.menu.items.length; i++) {
				var ck = this.categoryButton.menu.items.items[i];
				if (ck.attributes.layId==layer.layId) {
					if (ck.checked!=layer.checked) ck.setChecked(layer.checked);
				}
			}
			
			
		}		
	},

    /**
     * @method createTOC
     * 
     * 
     * @param {Object} obj
     * obj.
     * 
     */
    createTOC: function (obj) {

    	this.callParent(arguments);
		
		this.tocInfo.onEachCategory( 
	    	function(cat, catIdx) {	
    		
				    		//aggiungo bottone categoria
			    		this.categoryButton = new Ext.Button({
			    			text       : cat.catDescr,
							anchor     : '0',
							arrowAlign : 'bottom',
							iconAlign: 'top',
							cls        : 'bold',
							menu: {
				            	xtype: 'menu',
				            	cls: 'clearCSS'
							}
						});
						
						this.categoryButton.attributes = {};
			    		this.categoryButton.attributes.cat = catIdx;
			    		this.categoryButton.attributes.catId = cat.catId;
			    		this.categoryButton.attributes.lay = null;
			    		this.categoryButton.attributes.classi = null;
			    		
			    		this.add(this.categoryButton);
			    		
			    		var listenersCheckChange = {checkchange: {fn: this.checkItemChange, scope: this}};
		    			
			    		//aggiungo menu i cui item sono i layer della stessa
			    		for (var j=0; j<cat.layers.length; j++) {
			        			
			    			var layerItemMenu = new Ext.menu.CheckItem({
			        			text: cat.layers[j].descr,
								checked: cat.layers[j].checked,
								listeners: listenersCheckChange
							});
			        			
							layerItemMenu.attributes = {};			
							layerItemMenu.attributes.cat = catIdx;
			        		layerItemMenu.attributes.lay = j;
			        		layerItemMenu.attributes.codTPN = cat.layers[j].codTPN;
			        		layerItemMenu.attributes.layId = cat.layers[j].layId;
			        		layerItemMenu.attributes.classi = null;
			        		layerItemMenu.attributes.withOpacitySettings= cat.layers[j].withOpacitySettings;
							layerItemMenu.attributes.ownerTOC = this;
			    		
			        		this.categoryButton.menu.add(layerItemMenu);
			        		this.doLayout(true,true);
			    		}
		    	},
		    	this);
		
	}

});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


 Ext.define('modelloDatiStile', {
     extend: 'Ext.data.Model',
     requires: ['Ext.data.SequentialIdGenerator'],
     idgen: 'sequential',
     fields: [	'id',
	            'name',
	            'title',	
	            'styleAbstract',
	            'legendGraphic',
	            'sldtext'
		    ]
 });

/**
 * @class TolomeoExt.ToloStylePanel
 * @extends Ext.Window
 *
 */
Ext.define('TolomeoExt.ToloStylePanel', {

	extend: 'Ext.Window',
 
	
	/** 
	 * @property {String} TOLOMEOServer
	 * 
	 * 
	 */
	TOLOMEOServer: null,

	/** 
	 * @property {String} TOLOMEOContext
	 * 
	 * 
	 */
	TOLOMEOContext: null,
	
	/** 
	 * @property {String} TOLOMEOStaticRoot
	 * 
	 * 
	 */
	TOLOMEOStaticRoot: null,
	
	/** 
	 * @property {Object} layer
	 * 
	 * 
	 */
	layer: null,
	
	/**
	 * @property {Object} definedStyles
	 * @private 
	 * 
	 * 
	 */
	definedStyles: null,
	
	/**
	 * @property {Object} cat
	 * @private 
	 * 
	 * 
	 */
	cat:null,
	
	/**
	 * @property {Object} lay
	 * @private 
	 * 
	 * 
	 */
	lay: null,
	
	/**
	 * @property {Object} sldGrid
	 * @private 
	 * 
	 * 
	 */
	sldGrid: null,
	
	/**
	 * @property {Object} store 
	 * @private
	 * 
	 * 
	 */
	store: null,
	
	/**
	 * @property {Object} stylePreview
	 * @private 
	 * 
	 * 
	 */
	stylePreview: null,
	
	/**
	 * @method initComponent
	 * 
	 * 
	 */
	initComponent: function(){
	    
		//bottoni
		// Messo fisso false per non abilitare la funziona fino a che non è pronta
		if (false) { 
			this.btnNuovo = Ext.create('Ext.Button', {
	            text: ToloI18n.getMsg("ToloStylePanel.btnNuovo"),
		        disabled: false,
		        iconCls: 'iconConferma',
		        width: 75,
		        tooltip : {text: ToloI18n.getMsg("ToloStylePanel.btnNuovo.title"),
		        	title: ToloI18n.getMsg("ToloStylePanel.btnNuovo.msg")
		        },
		        listeners: { click: { fn: this.onCreaStile, scope: this}}
		    });
			
			this.btnImporta = Ext.create('Ext.Button', {
	            text: ToloI18n.getMsg("ToloStylePanel.btnImporta"),
		        disabled: false,
		        iconCls: 'iconConferma',
		        width: 75,
		        tooltip : {text: ToloI18n.getMsg("ToloStylePanel.btnImporta.msg")}, 
		        listeners: { click: { fn: this.onImportaStile, scope: this}}
		    });
			
			this.btnEsporta = Ext.create('Ext.Button', {
	            text: ToloI18n.getMsg("ToloStylePanel.btnEsporta"),
		        disabled: true,
		        iconCls: 'iconConferma',
		        width: 75,
		        tooltip : {text: ToloI18n.getMsg("ToloStylePanel.btnEsporta.msg")}, 
		        listeners: { click: { fn: this.onEsportaStile, scope: this}}
		    });
			
			this.btnModifica = Ext.create('Ext.Button', {
	            text: ToloI18n.getMsg("ToloStylePanel.btnModifica"),
		        disabled: true,
		        iconCls: 'iconConferma',
		        width: 75,
		        tooltip : {text: ToloI18n.getMsg("ToloStylePanel.btnModifica.msg")},
		        listeners: { click: { fn: this.onModificaStile, scope: this}}
		    });
		}	
		
		this.btnApplica = Ext.create('Ext.Button', {
					            text: ToloI18n.getMsg("ToloStylePanel.btnApplica"),
						        disabled: true,
						        iconCls: 'iconConferma',
						        width: 75,
						        tooltip : {text: ToloI18n.getMsg("ToloStylePanel.btnApplica.msg"), title: ToloI18n.getMsg("ToloStylePanel.btnApplica.title")},
						        listeners: { click: { fn: this.onApplica, scope: this}}
						    });
		
		this.btnAnnulla = Ext.create('Ext.Button',{
				            text: ToloI18n.getMsg("ToloStylePanel.btnAnnulla"),
				            width: 75,
							listeners: { click: { fn: this.nascondi, scope: this}}
				        });
		
		
		this.buttons = [this.btnNuovo, this.btnImporta, this.btnEsporta, this.btnModifica, this.btnApplica, this.btnAnnulla];
		
		
		this.formImporta = Ext.create('Ext.form.Panel', {
		    hidden: true,
		    renderTo: Ext.getBody(),
		    items: [{
		        xtype: 'filefield',
		        name: 'photo'
		        /*listeners:{
		            change:function( thiss, value, eOpts ){
		                  alert(value);
		                  //here place your ajax request
		            }
		         },*/
		        //fieldLabel: 'Photo',
		        //labelWidth: 50,
		        //msgTarget: 'side',
		        //allowBlank: false,
		        //anchor: '100%',
		        //buttonText: 'Select Photo...'
		    }
			]
		    });
		
		/*
		 * new Ext.create('Ext.form.field.File', {

            buttonOnly: true,
            hideLabel: true,
            buttonText: 'Carregar Playlist.',
            listeners: {
                'change': function(fb, v) {
                    form.getForm().submit({
                        method: 'POST',
                        url: 'carregaLista.php',
                    });
                }
            }
		 * 
		 */
		
		this.callParent(arguments);
		
		this.layout = 'border';
		this.addEvents('styleApply'); // selezionato stile e richiesta la sua applicazione
			
		this.store = Ext.create('Ext.data.JsonStore',{
		    autoDestroy: true,
		    autoSync: false,
		    model: 'modelloDatiStile'
		  //  storeId: 'myStore',
		    /*fields: [
	            'name',
	            'title',	
	            'styleAbstract',
	            'legendGraphic',
	            'sldtext'
		    ]*/
		});
		
		var columns =  [{
			header: ToloI18n.getMsg("ToloStylePanel.colNome"),
		    sortable: true, 
		    dataIndex: 'name'
		},{
	    	header: ToloI18n.getMsg("ToloStylePanel.colTit"),
			sortable: true, 
			dataIndex: 'title'
		},{
			header: ToloI18n.getMsg("ToloStylePanel.colDesc"),
		    sortable: true, 
		    dataIndex: 'styleAbstract',
		    renderer: function (val){
		    	return '<div style="white-space:normal !important;">'+ val +'</div>';
		    }
	    }];
		
		//griglia sld per layer selezionato
	    this.sldGrid = Ext.create('Ext.grid.GridPanel',{
		    	region: 'center',
		        frame: false,
		        height: 'auto',
		        store: this.store,
		        columns: columns,
		        viewConfig: {
		        		markDirty:false,
		    			forceFit: true,
		    			emptyText: ToloI18n.getMsg("ToloStylePanel.sldGrid.emptyText")
					},
				listeners: { selectionchange: { 
										fn: function(selmodel, selected, eOpts) {
												var bNessunaSelezione = (selected.length==0);
												var bCustomSld = !bNessunaSelezione && (selected[0].data.sldtext) && (selected[0].data.sldtext!="");
												this.btnApplica.setDisabled(bNessunaSelezione);
												if (this.btnEsporta) this.btnEsporta.setDisabled(!bCustomSld);
												if (this.btnModifica) this.btnModifica.setDisabled(!bCustomSld);
												
												if (bNessunaSelezione) {
													this.stylePreview.clearSrc();	
												} else {
													var rec = selected[0];
													if (rec.data.legendGraphic && !rec.data.legendGraphic=="") {
														this.stylePreview.setSrc(rec.data.legendGraphic);	
													} else {
														this.stylePreview.clearSrc();
													}
												}
											},
										scope: this
								}
							}
	       		        
	    	});
	    /*
	    this.sldGrid.getSelectionModel().on('selectionchange', function(selmodel, selected, eOpts) {
			var bNessunaSelezione = (selected.length==0);
			this.btnApplica.setDisabled(bNessunaSelezione);
	
			if (bNessunaSelezione) {
				this.stylePreview.clearSrc();	
			} else {
				var rec = selected;
				if (rec.data.legendGraphic && !rec.data.legendGraphic=="") {
					this.stylePreview.setSrc(rec.data.legendGraphic);	
				} else {
					this.stylePreview.clearSrc();
				}
			}
		}, this);
	    */
	    this.stylePreview = Ext.create('Ext.Panel', {
	    	title: ToloI18n.getMsg("ToloStylePanel.stylePreview.title"),
	    	autoScroll: true,
	    	split: true,
	    	collapsible: true,
	    	region: 'east',
    		width: '25%',
    		setSrc: function(src) {
				this.update('<img src="' + src +'" />');
    	    },
    	    clearSrc: function() {
    	    	this.update(ToloI18n.getMsg("ToloStylePanel.stylePreview.clear"));
    	    }
    	});
	    
	    this.add(this.sldGrid);
		this.add(this.stylePreview);
		
	},
	
	
	/**
	 * @method mostra
	 * 
	 * 
	 * @param {String} nome
	 * 
	 * 
	 * @param {Object} cat
	 * 
	 * 
	 * @param {Object} lay
	 * 
	 * 
	 * @param {Object} definedStyles
	 * 
	 * 
	 */
	mostra: function(layer, cat, lay, definedStyles) {
	
		this.layer = layer;
		this.lay = lay;
		this.cat = cat;
		this.definedStyles = definedStyles;
		
		// Aggiorno store con gli stili disponibili
		this.store.loadData(definedStyles);
		
		// Setto il titolo della finestra
		var title = ToloI18n.getMsg("ToloStylePanel.mostra.title", {nome: layer.nome});
		this.setTitle(title);
		
		// mostro la finestra
		this.show();
		
	},
			
	/**
	 * @method nascondi
	 * 
	 * 
	 */
	nascondi: function() {
		this.hide();
	},
	
	/**
	 * @method onImportaStile
	 * 
	 */
	onImportaStile: function(form) {
		var me = this;
		
		var formpanel = Ext.create('Ext.form.Panel', {
			url: this.TOLOMEOServer + this.TOLOMEOContext + '/MirrorServlet',
			bodyPadding: 10,
		    frame: true,
		    items: [{
		        xtype: 'filefield',
		        name: 'uploadfield',
		        allowBlank: false,
		        blankText: ToloI18n.getMsg("ToloStylePanel.onImportaStile.blankText"),
		        fieldLabel: "File",
		        labelWidth: 50,
		        buttonText: ToloI18n.getMsg("ToloStylePanel.onImportaStile.btnImporta"),
		        anchor: '100%',
				buttonConfig: {
					text: ToloI18n.getMsg("ToloStylePanel.onImportaStile.btnImporta"),
			        disabled: false,
			        iconCls: 'iconConferma',
			        //width: 75,
			        tooltip : {text: ToloI18n.getMsg("ToloStylePanel.onImportaStile.btnImporta.tooltip")}
				},
				buttonOnly: false}],
			buttons: [{
			        text: ToloI18n.getMsg("ToloStylePanel.onImportaStile.btnReset"),
			        handler: function() {
			            this.up('form').getForm().reset();
			        }
			    }, {
			        text: ToloI18n.getMsg("ToloStylePanel.onImportaStile.btnSubmit"),
			        formBind: true, //only enabled once the form is valid
			        disabled: true,
			        handler: function() {
			            var form = formpanel.getForm();
			            if (form.isValid()) {
			                form.submit({
			                    success: function(form, action) {
			                    	
			                        var s = TolomeoExt.Styler.StylePanel.sldToStyle(action.result.contenuto);
			                    	
			                    	me.store.add({
			                    		'name': s.name,
				        	            'title': s.title,
				        	            //'styleAbstract': 'abstract',
				        	            'legendGraphic': undefined,
				        	            'sldtext': action.result.contenuto
			                    	});
			        	       
			                       Ext.Msg.alert('Success', action.result.msg);
			                       formpanel.up('window').close();
			                    },
			                    failure: function(form, action) {
			                        Ext.Msg.alert('Failed', action.result.msg);
			                        formpanel.up('window').close();
			                    }
			                });
			            }
			        }
			    }]});
		        
		        
		    /*,
		        listeners:{
		            change:function( thiss, value, eOpts ){
		                  //alert(value);
		                  var form = formpanel.getForm();
		                  if(form.isValid()){
		                      form.submit({
		                          url: '/tolomeobinj/MirrorServlet',
		                          waitMsg: 'Importazione in corso',
		                          success: function(fp, o) {
		                        	  //  o.result.file 
		                              Ext.Msg.alert('Success', 'Importazione avvenuta con successo');
		                          },
		                          failure: function(form, action) {
		                              Ext.Msg.alert('Failed', action.result.msg);
		                          }
		                      });
		                  }
		            }
		         }*/
		        //fieldLabel: 'Photo',
		        //labelWidth: 50,
		        //msgTarget: 'side',
		        //allowBlank: false,
		        //anchor: '100%',
		        //buttonText: 'Select Photo...'
		    //}]});
		
		Ext.create('Ext.window.Window',{
			width: 400,
			resizable: false,
			height: 120,
			layout: 'fit',
			title: ToloI18n.getMsg("ToloStylePanel.onImportaStile.win.title"),
			items: [formpanel]
		}).show();
		 
		
		//var form = this.formImporta.getForm();
        
		
	},
	
	/**
	 * @method onEsporta
	 */
	onEsportaStile: function() {
		
	    var rec = this.sldGrid.getSelectionModel().getSelection()[0];
		
	    var formattedXml = this.formatXml(rec.data.sldtext);
	    
		var formpanel = Ext.create('Ext.form.Panel', {
			
			url:  this.TOLOMEOServer + this.TOLOMEOContext + '/MirrorServlet',
			standardSubmit: true,
			render: Ext.getBody(),
			hidden: true,
			items: [{
					    xtype: 'hiddenfield',
					    name: 'mode',
					    value: 'download'
					},{
					    xtype: 'hiddenfield',
					    name: 'contenuto',
					    value: formattedXml
					},{
					    xtype: 'hiddenfield',
					    name: 'filename',
					    value: rec.data.name + '.xml'
					}],
					
			buttons: [{
			        text: ToloI18n.getMsg("ToloStylePanel.onEsportaStile.btnReset"),
			        handler: function() {
			            this.up('form').getForm().reset();
			        }
			    }, {
			        text: ToloI18n.getMsg("ToloStylePanel.onEsportaStile.btnSubmit"),
			        formBind: true, //only enabled once the form is valid
			        disabled: true,
			        handler: function() {
			            var form = this.up('form').getForm();
			            if (form.isValid()) {
			                form.submit({
			                    success: function(form, action) {
			                       Ext.Msg.alert('Success', action.result.msg);
			                       formpanel.close();
			                    },
			                    failure: function(form, action) {
			                        Ext.Msg.alert('Failed', action.result.msg);
			                        formpanel.close();
			                    }
			                });
			            }
			        }
			    }]
		});
		
		formpanel.getForm().submit();
		
		
		
		/*
		Ext.create('Ext.window.Window',{
			width: 100,
			height: 60,
			layout: 'fit',
			title: 'ssss',
			items: [formpanel]
			
		}).show();
		*/
	},
	
	onModificaStile: function() {
		var rec = this.sldGrid.getSelectionModel().getSelection()[0];
		
		this.showStyle(rec);
	},
		
	/**
	 * @method onApplica
	 * 
	 * 
	 */
	onApplica: function() {
        var rec = this.sldGrid.getSelectionModel().getSelection()[0];
        if (rec!=null) this.fireEvent('styleApply', this.cat, this.lay, rec.data.name);
    
    },
    
    onCreaStile: function() {
    	//this.currentLegend.symbolType
    	
		//ALE Per ora commentato
		//this.currentLegend.rules.push(rule);
		//this.fireEvent("ruleadded", rule);
		this.showStyle(null);
    },
    
    showStyle: function(rec) {
		//console.log("prima delle modifiche ...");
		//logProperties(rule);
		//for (var symbolizerIndex = 0 ; symbolizerIndex < rule.symbolizers.length ; symbolizerIndex ++) {
		//	logProperties(rule.symbolizers[symbolizerIndex]);
		//}
    	var me = this;

		this.styleDialog = Ext.create("Ext.Window", {
			//title: "Stile \"" + (style.title || style.name || "Untitled") + "\"",
			layout: "fit",
			modal: true,
			width: 500,
			height: 500,
			constrainHeader: true,
			frame: false,
			//recordGriglia: rec,
			items: [{
				xtype: "styler_stylepanel",
				styleRecord: rec,
				layer: this.layer,
				mapPanel: this.mapPanel,
				listeners: {
					"stylecanceled": function() {
						this.styleDialog.close();
					},
					"stylesaved": function(rec) {
						
						if (me.store.getById(rec.get('id'))==null){
							//rec.set('name', 'sdsdsds');
							//rec.set('sldtext', sld);
							me.store.add([rec]);
						}/* else {
							me.store.add({
	                    		'name': 'nome',
		        	            'title': 'titolo',
		        	            'styleAbstract': 'abstract',
		        	            'legendGraphic': undefined,
		        	            'sldtext': sld
	                    	});
						}*/
                    	
                    	this.styleDialog.close();
						//console.log(format.write(sld));
					},
					scope: this
				}
			}]
		});
		
		
		this.styleDialog.show();
	},
	
	formatXml: function (xml) {
	    var formatted = '';
	    var reg = /(>)(<)(\/*)/g;
	    xml = xml.replace(reg, '$1\r\n$2$3');
	    var pad = 0;
	    Ext.Array.each(xml.split('\r\n'), function(node, index) {
	        var indent = 0;
	        if (node.match( /.+<\/\w[^>]*>$/ )) {
	            indent = 0;
	        } else if (node.match( /^<\/\w/ )) {
	            if (pad != 0) {
	                pad -= 1;
	            }
	        } else if (node.match( /^<\w[^>]*[^\/]>.*$/ )) {
	            indent = 1;
	        } else {
	            indent = 0;
	        }
	 
	        var padding = '';
	        for (var i = 0; i < pad; i++) {
	            padding += '  ';
	        }
	 
	        formatted += padding + node + '\r\n';
	        pad += indent;
	    });
	 
	    return formatted;
	}

});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110�1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo � un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo � un software libero; � possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo � distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILIT� o
 IDONEIT� PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110�1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo � sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

// @include "include.js"

/**
 * @class TolomeoExt.ToloQueryPanelExt
 * Pannello per contenere una mappa. Funzioni pubbliche di query e posizionamento (es. ricerca via e civico etc.).
 * Quando viene attivata la ricerca viene mostrato un pannello che contiene l'elenco delle ricerche possibili, 
 * che permette di inserire i criteri di ricerca all'interno di quelli previsti, di lanciare la ricerca. Nel caso che il risultato sia univoco
 * viene evidenziato l'oggetto risultato della ricerca e viene fatto uno zoomToHighlighted. Nel caso il risultato non sia univoco viene visualizzato 
 * l'elenco per poter scegliere quale oggetto evidenziare e zoomare.
 * Le ricerche possibili sono controllate da contenuto del file di configurazione xml, che permette di selezionare quali tra le ricerche
 * disponibili nel package sit debbano essere attivate.
 *
 * @author Ing. Alessandro Radaelli
 */
Ext.define('TolomeoExt.ToloQueryPanelExt', {

	extend: 'Ext.Panel',
	
	//requires: [],


	/** 
	 * @property {Object} showHideContainer
	 * contenitore che deve essere mostrato/nascosto per visualizzare o nascondere la legenda
	 * Se null viene visualizzato e nascosto questo stesso pannelleo
	 * 
	 */
	showHideContainer: null,

	/** 
	 * @property {Function} showHandler
	 * Funzione da chiamare per visualizzare la legenda. Se null non viene chiamata
	 * 
	 */
	showHandler: null,

	/** 
	 * @property {Function} hideHandler
	 * Funzione da chiamare per nascondere la legenda. Se null non viene chiamata
	 * 
	 */
	hideHandler: null,

	/** 
	 * @property {Object} paramsJS
	 * 
	 * 
	 */
	paramsJS: null,

	/** 
	 * @property {String} TOLOMEOServer
	 * 
	 * 
	 */
	TOLOMEOServer: null,

	/** 
	 * @property {String} TOLOMEOContext
	 * 
	 * 
	 */
	TOLOMEOContext: null,

	/** 
	 * @property {Object} panelCampi
	 * 
	 * 
	 */
	panelCampi: null,

	/** 
	 * @property {Object} panelResults
	 * 
	 * 
	 */
	panelResults: null, 

	/** 
	 * @property {Object} formPanelSearch
	 * 
	 * 
	 */
	formPanelSearch: null,

	/** 
	 * @property {Object} layerStore
	 * 
	 * 
	 */
	layerStore: null,

	/** 
	 * @property {Object} cmbLayerSel
	 * 
	 * 
	 */
	cmbLayerSel: null,

	/** 
	 * @property {Object} cmbTipo
	 * 
	 * 
	 */
	cmbTipo:null,

	/** 
	 * @property {Object} pnlCampi
	 * 
	 * 
	 */
	pnlCampi: null, 

	/** 
	 * @property {Object} pnlResults
	 * 
	 * 
	 */
	pnlResults: null,

	/** 
	 * @property {Object} suggestWithGeom
	 * 
	 * 
	 */	
	suggestWithGeom: null,
	
	/** 
	 * @property {Object} queryFields
	 * 
	 * 
	 */	
	queryFields: null,

	/** 
	 * @property {Object} waitMask
	 * 
	 * 
	 */	
	waitMask: null,
	
	/** 
	 * @property {Object} geomFilterField
	 * Campo nascosto che ospiterà geomFilter
	 * 
	 */
	geomFilterField: null,
	
	/**
	 * @method initComponent
	 * Crea un nuovo TolomeoExt.ToloQueryPanelExt
	 * 
	 */
	initComponent: function(){
	
    	// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		TolomeoExt.applyIfEmpty(this, {suggestWithGeom: true});
		
		this.on('activate', this.focusFirstField);
		
		// Eventi
		// Item selected
    	this.addEvents('querySelected');
    	// No results
    	this.addEvents('queryNoResults');
    	// Hover on item of a selection with multiple results
    	this.addEvents('queryMultipleResultHover');
    	this.addEvents('queryMultipleResultOut');
    	
    	// Evento che scatta quando un nuovo campo filtro geometria è creato
    	// Tipicamente è utilizzato per consentire alla API di inizializzarlo con il box 
    	// utilizzando il metodo setGeomFilterField
    	this.addEvents('geomFilterFieldCreated');
    	
		this.layerStore = Ext.create('Ext.data.Store',{
		    fields: [{
		    	name: 'descrizioneLayer',
		    	mapping: 'descrizioneLayer'
		    },{
		    	name: 'codTPN', mapping: 'codTPN'
		    },{
		    	name: 'eventiLayer',
		        convert: function (v, rec) { 
		        	return rec.raw; 
		        } 
		    }],
		    data: this.paramsJS.azioniEventi.eventiLayerList
		});
		
		this.layerStore.filterBy(this.withSearchLayerFilter);

		this.cmbLayerSel = Ext.create('Ext.form.ComboBox',{
			typeAhead: true,
			forceSelection: true, 
			anchor: "-1",
			lastQuery: '',
			queryMode: 'local',
			triggerAction: 'all',
			emptyText: ToloI18n.getMsg("ToloQueryPanelExt.cmbLayerSel.emptyText"),
			selectOnFocus: true,
			editable:false,
			fieldLabel: ToloI18n.getMsg("ToloQueryPanelExt.cmbLayerSel.fldLabel"),
			//hiddenName: 'codTPN',
			name: 'codTPN',
			valueField: 'codTPN',
			displayField: 'descrizioneLayer',
			listeners: {
				select: {
					fn: this.onQueryChangeLayer,
					scope: this
				}
			},
			store: this.layerStore
		});
		
		this.SearchTypeStore = Ext.create('Ext.data.Store',{
			fields: [{
		    	name: 'metadatoRicerca',
		    	mapping: 'metadatoRicerca'
		    },{
		    	name: 'id',
		    	convert: function (v, rec) { 
		    		return rec.raw.metadatoRicerca.id; 
		    	}
		    },{
		    	name: 'desc',
		    	convert: function (v, rec) { 
		    		return rec.raw.metadatoRicerca.descrizione; 
		    	}
		    },{
		    	name: 'azioniEventiRicercaList',
		    	convert: function (v, rec) { 				        
		    		return rec.raw; 
		    	}
		    }]
		});
				
		this.cmbTipo = Ext.create('Ext.form.ComboBox',{
			typeAhead: false,
			anchor: "-1",
			editable: true,
			triggerAction: 'all',
			queryMode: 'local',
			fieldLabel: ToloI18n.getMsg("ToloQueryPanelExt.cmbTipo.fldLabel"),
			editable:false,
			//hiddenName: 'idRicerca',
			name: 'idRicerca',
			valueField: 'id',
			displayField: 'desc',
			listeners: {
				select: {fn: this.onQueryChangeRicerca, scope: this}
			},
			store: this.SearchTypeStore
		});
		
		this.pnlCampi = Ext.create('Ext.Panel',{
			anchor: "-1",
			border: false,
		//	monitorResize: true,
			layout: "form",
			hidden: false,
			reset: function(){
				this.items.each(function(item){
					if (item.name != 'geomFilter') {
						item.reset();
					}
				});
			}
		}); 
			
		// FieldSet
		this.fs= Ext.create('Ext.form.FieldSet',{
		//	monitorResize: true,
			title: ToloI18n.getMsg("ToloQueryPanelExt.fldSet"),
			anchor: "-1",
			autoWidth: true,
			autoHeight: true,
			defaultType: 'textfield',
			items:[this.cmbLayerSel, this.cmbTipo, this.pnlCampi]
		});

		this.pnlResults = Ext.create('Ext.Panel',{
			title: ToloI18n.getMsg("ToloQueryPanelExt.pnlResults"),
			frame: false,
			hidden: true,
	        layout: 'fit',
	        autoWidth: true,
	        autoScroll: true,
	        height: 300
		});
		
		// FormPanel
		this.formPanelSearch = Ext.create('Ext.FormPanel',{
			monitorValid: true,
		//	monitorResize: true,
			labelWidth: 60,
			standardSubmit: false,
			bodyStyle: 'padding: 5px',
			border: false,
			items: [this.fs, {
				xtype: 'hidden', 
				name: 'SRID',
				value : this.paramsJS.mappe.SRID
			}],
			buttons: [{
				text: ToloI18n.getMsg("ToloQueryPanelExt.btnTrova"),
				formBind: true,
				type: 'button',
				listeners: {'click': {fn: this.onQuery, scope: this}}
			},{
				text: ToloI18n.getMsg("ToloQueryPanelExt.btnPulisci"),
				resultPanel: this.pnlResults,
				fieldsPanel: this.pnlCampi,
				handler: function() {
					this.fieldsPanel.reset();
					this.resultPanel.hide();
				}
			}]/*,
			keys: [{
	        	key: [Ext.EventObject.ENTER], 
             	handler: this.onQuery,
                scope: this
             }] */ 
		});
		
		var map = Ext.create('Ext.util.KeyMap',{
		    target: this,
		    binding: {
		        key: Ext.EventObject.ENTER,
		        fn: this.onQuery,
		        scope: this
		    }
		});		

		
		this.callParent();
		
		// Se esiste seleziono il primo layer
    	if (this.layerStore.getCount()>0) {
    		this.cmbLayerSel.setValue(this.layerStore.getRange(0,0)[0].data.codTPN);
    		this.onQueryChangeLayer (this.cmbLayerSel, this.layerStore.getRange(0,0)[0], 0 );
    	}
    	else //altrimenti nascondo la lista
    		this.cmbLayerSel.setVisible(false);
		
    	this.add(this.formPanelSearch);
    	this.add(this.pnlResults);
    		
	   // this.addButton(this.cmbLayerSel);
    },
    
    /**
     * @method formSubmit
     * Metodo relativo alla gestione Ext.
     * 
     */
    formSubmit: function() {
    	
    	var fparams = this.formPanelSearch.getForm().getValues();
    	fparams.format = "ext";
    	
    	var submitOpt = {
    		url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxQueryServlet',
    		method: 'POST',
    		params: fparams,
    		waitMsg: ToloI18n.getMsg("ToloQueryPanelExt.formSubmit.wait"),
    		success: this.doOnQueryAjaxCallback,
    		failure: this.doOnQueryAjaxFailure,
    		scope: this
    	};
    	
    	// Submit ajax della form

    	this.waitMask=new Ext.LoadMask(this.id, {msg:ToloI18n.getMsg("ToloQueryPanelExt.formSubmit.wait")});
    	this.waitMask.show();
		new TolomeoExt.ToloCrossAjax().request(submitOpt);
		//this.formPanelSearch.getForm().submit(submitOpt);
    },
    
    /**
     * @method withSearchLayerFilter
     * Metodo relativo alla gestione Ext.
     *
     * @param {Object} record
     * record.
     * 
     */
    withSearchLayerFilter: function(record) {
    	return (record.data.eventiLayer.azioniEventiRicercaList.ricercaList.length!=0);
    },

    /**
     * @method showQuery
     * Metodo relativo alla gestione Ext.
     * 
     */
    showQuery: function () {
    	if (this.showHandler!=null) {
			this.showHandler.call(this);
		} else if (this.showHideContainer!=null) {
			this.showHideContainer.setVisible(true);
		} else this.setVisible(true); 	
    },

    /**
     * @method hideQuery
     * Metodo relativo alla gestione Ext.
     * 
     */
    hideQuery: function () {
    	//this.onQueryChangeLayer();
    	if (this.hideHandler!=null) {
			this.hideHandler.call(this);
		} else if (this.showHideContainer!=null) {
			this.showHideContainer.setVisible(false);
		} else this.setVisible(false); 
    },
    
    /**
     * @method showAjaxError
     * Metodo relativo alla gestione Ext.
     * 
     * @param {Object} transport
     * transport.
     */
    showAjaxError: function(transport){			
		Ext.Msg.show({
		    title: ToloI18n.getMsg("ToloQueryPanelExt.showAjaxError.title"),
		    msg: ToloI18n.getMsg("ToloQueryPanelExt.showAjaxError.msg"),
		    buttons: {		    	
			    yes: ToloI18n.getMsg("ToloQueryPanelExt.showAjaxError.btnMostra"),
			    cancel: ToloI18n.getMsg("ToloQueryPanelExt.showAjaxError.btnContinua")						    
		    },
		    icon: Ext.MessageBox.ERROR,
		    fn: function(btn) {
		    	switch(btn) {
		       		case 'yes':
		       			Ext.Msg.alert(ToloI18n.getMsg("ToloQueryPanelExt.showAjaxError.title"),transport.responseText);
		       			break;
		    	}
		    }
		});
		this.fireEvent('ajaxError', transport);						
	},

	/**
	 * @method onQueryChangeLayer
	 * Funzione chiamata quando nel pannello di query viene cambiato il layer selezionato.
	 * Provvede ad aggiornare l'elenco delle ricerche disponibili.
	 *
	 * @param {Ext.form.ComboBox} combo
	 * combo.
	 * 
	 * @param {Ext.data.Record} record
	 * record.
	 * 
	 * @param {Number} index
	 * index.
	 * 
	 */
	onQueryChangeLayer: function (combo, record, index ) {

		 var recbuff;
		 if (record instanceof Array) {
			 recbuff=record[0];
		 } else {
			 recbuff = record;
		 }
		 
		var queryList = recbuff.data.eventiLayer.azioniEventiRicercaList.ricercaList;
		var store = this.cmbTipo.store;
		
		//store.removeAll();
		store.loadData( queryList, false);

		// Se esiste seleziono prima scelta
		if (store.getCount()>0) {
			if(store.getCount() == 1){
    			this.cmbTipo.hide();
    		}else{
    			this.cmbTipo.show();
    		}
			this.cmbTipo.select(store.data.items[0]);
    		
			//this.cmbTipo.setValue(store.getRange(0,0)[0].data.id);
        	this.onQueryChangeRicerca (this.cmbTipo, store.getRange(0,0)[0], 0 );
		}
	}, 

	/**
	 * @method onQueryChangeRicerca
	 * Funzione chiamata quando nel pannello di query viene cambiata la ricerca selezionata.
	 * Provvede ad aggiornare l'elenco dei campi di ricerca e ad inizializzare, se disponibile, il meccanismo di suggest.
	 *
	 * @param {Ext.form.ComboBox} combo
	 * combo.
	 * 
	 * @param {Ext.data.Record} record
	 * record.
	 * 
	 * @param {Number} index
	 * index.
	 * 
	 */
	onQueryChangeRicerca: function (combo, record, index) {
		var me = this;
		
		var recbuff;
		if (record instanceof Array) {
			recbuff=record[0];
		} else {
			recbuff = record;
		}
		
		var nomiCampi = recbuff.data.metadatoRicerca.nomiCampi;
		var suggestDisponibile = recbuff.data.metadatoRicerca.suggestDisponibile;
		var suggestMinLength = recbuff.data.metadatoRicerca.suggestMinLength;
		var suggestProvider = recbuff.data.metadatoRicerca.suggestProvider;
		//var tipiCampi = query.metadatoRicerca.tipiCampi;
		
		this.pnlResults.hide();
		this.pnlCampi.removeAll();
		this.pnlCampi.hide();
		this.queryFields = [];

		// Inserimento campi e labels
		for (var i=0; i<nomiCampi.length; i++) {
			
			var proxy = TolomeoExt.ToloCrossAjaxUtil.getProxy(null, this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxSuggestServlet');
			proxy.extraParams= {
	        	format:"ext",
	        	idCampo: i,
	        	SRID: this.paramsJS.mappe.SRID,
	        	withGeom: this.suggestWithGeom
	        };
			
			var ds = Ext.create('Ext.data.JsonStore',{
		        proxy: proxy,
		        idCampo: i,
				listeners: {
					beforeload: {
						fn: function(store, options) {
							return me.setAutoCompleteBaseParams(store, options);  
						}
					},
					load: {
						fn: function(store, records, options) {
							store.sort('descriptionSuggest'+store.idCampo,'ASC');
						}
					}
				}
		    });
			var a = new TolomeoExt.ToloCrossAjax();
			
			ds.on('exception', a.storeException);
			
			
		    var field1 = null;
		    var fldopts = {
				fieldLabel: nomiCampi[i],
				name: 'campoRicerca' + i,
				allowBlank: false
			};
			
			var fldoptskey = {
				name: 'campoRicercaChiave' + i
			};
		    
		    // Se autosuggest
		    if ( (suggestDisponibile!=undefined) && (suggestDisponibile!=null) && (suggestDisponibile.size!=0) && suggestDisponibile[i]) {
		    
		    	if ( (suggestProvider!=undefined) && (suggestProvider!=null) && (suggestProvider.size!=0) && suggestProvider[i]!=null) {
		    	// suggest provider definito
		    		
		    		var filterBind 	= suggestProvider[i].filterBind;
		    		var fields 		= [];
		    		if (suggestProvider[i].valori.length>0) {
		    			for(var propertyName in suggestProvider[i].valori[0]) {
			    			fields.push(propertyName);
			    		}	
		    		} else {
		    			fields 		= ['COD', 'DESC'];
		    		}
		    		
		    		var store = Ext.create('Ext.data.JsonStore',{
		    		    // store configs
		    		    autoDestroy: true,
		    		    data: suggestProvider[i],
		    		    fields: fields, 
		    		    proxy: {
		    		    	type: 'memory',
		    		    	// reader configs
		    				reader: {
		    		    			type: 'json',
		    		    			root: 'valori'
		    		    			//idProperty: suggestProvider[i].valueFieldName // 'COD',
		    		    			//fields: fields //['COD', 'DESC', 'REG']
		    				}
		    			}
		    		});
		    		var field1key = Ext.create('Ext.form.field.Hidden',fldoptskey);
		    		this.pnlCampi.add(field1key);
		    		Ext.apply(fldopts, {
						forceSelection: true,
						lastQuery: '',
						store: store,
						displayField: suggestProvider[i].displayFieldName, //'DESC',
				        valueField: suggestProvider[i].valueFieldName, //'COD',
				        queryMode: 'local',
						selectOnFocus: true,
						editable:true,
						triggerAction: 'all',
						//queryParam: 'q',
				        typeAhead: true,
				        loadingText: ToloI18n.getMsg("ToloQueryPanelExt.onQueryChangeRicerca.loadingText"),
				        field1key: field1key,
				        anchor: "-3",
				        minChars: suggestMinLength[i],
		    			//hiddenName: 'campoRicerca' + i,		// invia con la form il valueField invece del contenuto del campo
		    			filterBind: filterBind,
		    			fieldIdx: i,
		    		    //listeners: { beforeQuery: { fn: function() { 
		    		    //									me.storeFilterApply(this.store, this.filterBind);} } }
		    			listeners: { change: { fn: function() { 
		    				me.suggestUpdate(suggestProvider, this);} 
		    				},
		    						 select: { 
				        					   fn: function( combo, records, eOpts ) {
					        						combo.field1key.setValue(records[0].get('key'));	
					        					},
					        					scope: this
				        					},
				        			 afterrender: { fn: function() { me.suggestUpdate(suggestProvider, this);} }
		    			}
			    	});
			    	
			    	
		    		field1 = Ext.create('Ext.form.ComboBox',fldopts);
		    		 
		    	} else {
		    		// senza suggest provider (meccanismo classico con AjaxSuggestServlet)
			    	var field1key = Ext.create('Ext.form.field.Hidden',fldoptskey);
		    		this.pnlCampi.add(field1key);
		    		Ext.apply(fldopts, {
						forceSelection: true, 
						store: ds,
				        displayField: 'descriptionSuggest' + i,
				        //valueField: 'key',
				        queryParam: 'q',
				        typeAhead: false,
				        loadingText: ToloI18n.getMsg("ToloQueryPanelExt.onQueryChangeRicerca.loadingText"),
				        anchor: "-3",
				        minChars: suggestMinLength[i],
				        hideTrigger:true,
				        field1key: field1key,
				        listeners: { select: {  
				        						fn: function( combo, records, eOpts ) {
					        						combo.field1key.setValue(records[0].get('key'));	
					        					},
					        					scope: this
				        					}
				        			}
			    		});
		    		field1 = Ext.create('Ext.form.ComboBox',fldopts);		
		    		
		    	}
		    }else {
			    field1 = Ext.create('Ext.form.TextField',fldopts);
		    }
		   
		    this.queryFields.push(field1);
			this.pnlCampi.add(field1);			
			if (i==0) field1.focus(false, 20);			
		}
		
		// Inserimento checkbox per filtro geografico
		if (recbuff.data.metadatoRicerca.geomFilterAvailable) {
			this.pnlCampi.add({
		                        boxLabel  : ToloI18n.getMsg("ToloQueryPanelExt.cercamappavis"),
		                        name      : 'geomFilterActive',
		                        xtype	  : 'checkboxfield'
		                    });
			
			this.geomFilterField = Ext.create('Ext.form.field.Hidden', {
                name      : 'geomFilter'
            });
			
			this.pnlCampi.add(this.geomFilterField);
			
			this.fireEvent('geomFilterFieldCreated', this.geomFilterField);
		}
		
		
		this.pnlCampi.setVisible(true);
		this.pnlCampi.doLayout();
	},

	/**
	 * @method arrayContains
	 * 
	 *
	 * @param {Object} arr
	 * 
	 * 
	 * @param {Object} obj
	 * 
	 * 
	 */
	arrayContains: function(arr, obj) {
		var retVal=false;
		for (var i=0; i<arr.length; i++) if (arr[i]==obj) retVal=true;
		
		return retVal;
	},

	/**
	 * @method suggestUpdate
	 * 
	 *
	 * @param {Object} suggestProvider
	 * 
	 * 
	 * @param {Object} changedField
	 * 
	 * 
	 */
	suggestUpdate: function(suggestProvider, changedField) {
		var dipendonoDa = [];
		var changedIdx = changedField.fieldIdx;
		
		for (var i=0; i<suggestProvider.length; i++) {
			
			if (changedIdx!=i) {
				//suggest del campo escluso changedIdx stesso
				var s = suggestProvider[i].filterBind;
				// Numerocampo#nomecampo 
				var s1 = s.split(",");
				for (var j=0; j<s1.length; j++) {		
					var s2 = s1[j].split("#");
					var numeroCampo = s2[0];
					if (numeroCampo==changedIdx) {
						// Il campo numeroCampo dipende da changedIdx
						// Controllo se c'� gi� altrimenti aggiungo nella lista 
						if (!this.arrayContains(dipendonoDa, numeroCampo)) dipendonoDa.push(i);
					}					
				}
			}
			
		}
		
		// Aggiorna lo storeFilter per ogni campo che dipende dal campo che � cambiato		
		for (var i =  0; i<dipendonoDa.length; i++) {
			var numCampo = dipendonoDa[i];
			this.storeFilterApply(this.queryFields[numCampo]);
		}
	},

	/**
	 * @method storeFilterApply
	 * 
	 *
	 * @param {Object} field
	 * 
	 * 
	 */
	storeFilterApply: function(field ) {
		var store		= field.store;
		var filterBind 	= field.filterBind;
					
		if (filterBind==undefined || filterBind==null || filterBind=="") return;
		
		field.setValue("");
		var filters = filterBind.split(",");
		var filtriExt = [];
		for (var i = 0; i<filters.length; i++) {
			var f = filters[i].split("#");
			if (this.queryFields[f[0]].getValue()!="") {
				var filtroExt = {
								root: 'data',
								property     : f[1],
				                value        : this.queryFields[f[0]].getValue(),
				                anyMatch     : true, //optional, defaults to true
				                caseSensitive: true  //optional, defaults to true
							};
				filtriExt.push(Ext.create('Ext.util.Filter',filtroExt));
			}
		}
		if (filtriExt.length != 0) {
			store.clearFilter(true);
			store.filter(filtriExt);
		} else {
			store.clearFilter(filtriExt);
		}
		
		
	},
	
	/**
	 * @method setAutoCompleteBaseParams
	 * 
	 * 
	 * @param {Object} ds
	 * ds.
	 * 
	 * @param {Object} options
	 * options.
	 * 
	 */
	setAutoCompleteBaseParams: function(ds, options) {
		
		ds.getProxy().extraParams = ds.getProxy().extraParams || {};
		Ext.apply(ds.getProxy().extraParams,{
			codTPN: this.cmbLayerSel.getValue(),
			idRicerca: this.cmbTipo.getValue()
		});
		//ds.setBaseParam('codTPN', this.cmbLayerSel.getValue());
		//ds.setBaseParam('idRicerca', this.cmbTipo.getValue());

		// necessario dalla versione 3.1 di extJS
		options.params.codTPN = this.cmbLayerSel.getValue();
		options.params.idRicerca = this.cmbTipo.getValue();
		
		for (var i=0; i<this.pnlCampi.items.items.length; i++) {
			var cmp = this.pnlCampi.items.items[i];
			ds.getProxy().extraParams[cmp.name] = cmp.getValue(); 
			options.params[cmp.name] = cmp.getValue();
		}
		
		return true;
	},
	
	/**
	 * @method focusFirstField
	 * 
	 * 
	 */
	focusFirstField:function() {
		if ( this.pnlCampi && this.pnlCampi.items && this.pnlCampi.items.items.size>0) this.pnlCampi.items.items[0].focus(false, 30); 	
	},	

	/**
	 * @method onQuery
	 * Esegue la ricerca tramite ajax sulla base dei valori contenuti nel pannello di query.
	 * Questa funzione si occupa solo di eseguire la chiamata ajax, che viene poi gestita da doOnQueryAjaxCallback.
	 * 
	 */
    onQuery: function () {
    	// Svuoto lista risultati precedenti
    	if (this.pnlResults) this.pnlResults.removeAll();

    	this.formSubmit();
    },

    /**
     * @method doOnQueryAjaxCallback
     * Funzione di callback della chiamata Ajax che effettua la ricerca onQuery.
     *
     * @param {Object} results
     * risposta della chiamata ajax.
     * 
     * @param {Object} store
     * store.
     * 
     */
    doOnQueryAjaxCallback: function (results, store) {

    	this.waitMask.hide();
    	if(results.length == 0){
    		this.onQueryNoResults();
    	} else if (results.length == 1) {
    		var geoms = new JSGeometryArray();
    		geoms.FromStore(results, store);
    		if (geoms.geometries[0].geometry=="") {
    			Ext.Msg.alert(ToloI18n.getMsg("ToloQueryPanelExt.doOnQueryAjaxCallback.title"),ToloI18n.getMsg("ToloQueryPanelExt.doOnQueryAjaxCallback.msg")).getDialog().focus();
    		}else{
    			this.onQuerySingleResult(geoms);
    		}
    	} else {
    		this.onQueryMultipleResults(results, store);
    	}
    },

    /**
     * @method doOnQueryAjaxFailure
     * Funzione di gestione errore avvenuto nella chiamata Ajax che effettua la ricerca onQuery.
     * 
     * @param {Object} store
     * store.
     * 
     */
    doOnQueryAjaxFailure: function (store) {
    	this.waitMask.hide();
    	//showAjaxError(transport);
    },

    /**
     * @method onQuerySingleResult
     * Gestisce la risposta della query; se si tratta di risposta univoca esegue le azioni previste chiamando la funzione doEventActions, 
     * nel caso di risposta multipla chiama onQueryMultipleResults.
     * 
     * @param {TolomeoExt.JSGeometryArray} geoms
     * Oggetti risultato della ricerca.
     * 
     */
    onQuerySingleResult: function (geoms) {		
    	this.fireEvent('querySelected', geoms);
    },

    /**
     * @method onQueryNoResults
     * Gestisce il caso in cui la ricerca non abbia dato dei risultati.
     * 
     */
    onQueryNoResults: function () {
 		this.fireEvent('queryNoResults');
 		//.getDialog()
 		Ext.MessageBox.alert(ToloI18n.getMsg("ToloQueryPanelExt.onQueryNoResults.title"), ToloI18n.getMsg("ToloQueryPanelExt.onQueryNoResults.msg")).focus();
    },

    /**
     * @method onQueryMultipleResults
     * Gestisce il caso di ricerca con pi� di un risultato visualizzando la lista e fornendo le funzionalit� per fare zoom all'intero 
     * insieme dei risultati, o al singolo.
     *
     * @param {Object} results
     * results
     * 
     * @param {Object} store
     * store
     * 
     */
    onQueryMultipleResults: function(results, store) {

    	this.pnlResults.setVisible(true);
    	
    	var listView = Ext.create('Ext.grid.Panel',{
    		store: store,
    		autoWidth: true,
    		emptyText: ToloI18n.getMsg("ToloQueryPanelExt.onQueryMultipleResults.emptyText"),
    		viewConfig: {
    			//firstCls: null,
    			trackOver: true
    		},
    		
    		//reserveScrollOffset: true,
    		//multiSelect: false,
    		listeners: {
    			'itemmouseenter': { fn: this.onQueryAddHighlighted, scope: this},
    			'itemmouseleave': { fn: this.onQueryClearHighlighted, scope: this},
    			'itemclick':      { fn: this.onQuerySingleResultByIndex, scope: this}
    		},
    		columns: [{
    			header: ToloI18n.getMsg("ToloQueryPanelExt.onQueryMultipleResults.colDesc"),
    			//width: 1,
    			flex: 1,
    			dataIndex: 'description'
    		}]
    	});

    	store.sort('description', 'ASC');
    	this.pnlResults.add(listView);
    	this.pnlResults.doLayout();
    }, 

    /**
     * @method onQuerySingleResultByIndex
     * Funzione che permette di estrerre il singolo oggetto nella lista dei risultati della query.
     * 
     * @param {Object} listView
     * listView
     * 
     * @param {Object} record
     * 
     * 
     * @param {Object} item
     * 
     * 
     * @param {Object} index
     * index
     * 
     * @param {Object} e
     * l'evento
     * 
     * @param {Object} eOpts
     * 
     * 
     */
    onQuerySingleResultByIndex: function (listView, record, item, index, e, eOpts) {
    	var geom = record.data; 
    		//listView.store.data.items[index].data;     	
    	var jsGeoArr = new JSGeometryArray();
    	jsGeoArr.FromStoreSingleRecord(geom);

    	this.onQuerySingleResult(jsGeoArr);
    },

    /**
     * @method onQueryAddHighlighted
     * Evidenzia il singolo oggetto identificato da index all'interno del risultato della query. Viene invocato sull'evento onmouseover sulla lista dei risultati.
     *
     * @param {Object} listView
     * listView
     * 
     * @param {Object} record
     * 
     * 
     * @param {Object} item
     * 
     * 
     * @param {Object} index
     * index
     * 
     * @param {Object} e
     * l'evento
     * 
     */
    onQueryAddHighlighted: function (listView,  record, item, index, e, eOpts) {

    	//store.data.items[index].data;
    	var geom = record.data;
    	var jsGeoArr = new JSGeometryArray();
    	jsGeoArr.FromStoreSingleRecord(geom);

    	this.fireEvent('queryMultipleResultHoverStart', jsGeoArr.geometries[0]); 
    	/*
    	TODO su chi ascolta evento
    	var geoms   = document.getElementById("divQueryListaRisultati").geoms;		

    	addHighlighted(geoms.geometries[index]);
    	 */

    },

    /**
     * @method onQueryClearHighlighted
     * Viene invocato sull'evento onmouseout sulla lista dei risultati per eseguire eventualmente operazione di deselezione. Attualmente non esegue alcuna operazione.
     *
     * @param {Object} listView
     * listView
     * 
     * @param {Object} record
     * 
     * 
     * @param {Object} item
     * 
     * 
     * @param {Object} index
     * index
     * 
     * @param {Object} e
     * l'evento
     * 
     * @param {Object} eOpts
     * 
     * 
     */
    onQueryClearHighlighted: function (listView, record, item, index, e, eOpts) {
    	var geom = record.data; 
    	var jsGeoArr = new JSGeometryArray();
    	jsGeoArr.FromStoreSingleRecord(geom);
    	
    	this.fireEvent('queryMultipleResultOut', jsGeoArr.geometries[0] ); 
    },


    /**
     * @method setGeomFilterField
     * 
     *
     * @param {Object} geom
     * 
     * 
     */
    setGeomFilterField: function(geom) {
    	if (this.geomFilterField) {
    		this.geomFilterField.setValue(geom);
    	}
    	
    }
    
    /*
     * @method onQueryZoomOggetto
     * Esegue lo zoom all'elemento individuato da index all'interno del risultato della query.
     * TODO su ci ascolta il relativo evento
     *
     * @param {Number} index
     * index
     * 
     onQueryZoomOggetto: function (index){
     	var geoms   = document.getElementById("divQueryListaRisultati").geoms;
     	if (index || index == 0) {
     		zoomToExtent(geoms.geometries[index].boundingbox);
     	} else {
     		zoomToExtent(geoms.boundingbox);
     	}	
     }*/
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * Class: TolomeoExt.ToloButtonPanelExt
 * 
 * Inherits from:
 *  - <Ext.Toolbar>
 *
 */

Ext.define('TolomeoExt.ToloButtonPanelExt', { 
//TolomeoExt.ToloButtonPanelExt = Ext.extend(Ext.Toolbar,{

	extend: 'Ext.Toolbar',
	//requires: [],
	
	/**
	 * Settato automaticamente da bindToApi. 
	 * @type {TolomeoExt.ToloMapAPIExt}
	 */
	api: null,
	
	/** 
	 * Property: paramsJS
	 * {JSONObject} 
	 */
	paramsJS:null,

	/** 
	 * Property: TOLOMEOServer
	 * {String} 
	 * 
	 */
	TOLOMEOServer: null,

	/** 
	 * Property: TOLOMEOContext
	 * {String}
	 * 
	 */
	TOLOMEOContext: null,

	/** 
	 * Property: withPan
	 * {Boolean} Indica se il pulsante "Pan" deve essere presente.
	 */
	withPan: true,

	/** 
	 * Property: withPanArrows
	 * {Boolean} Indica se i pulsanti "PanNord", "PanEst", "PanSud" e "PanOvest" deve essere presente
	 */
	withPanArrows: false,

	/** 
	 * Property: withNavHistory
	 * {Boolean} Indica se i pulsanti di navigation history sono attivi.
	 */
	withNavHistory: true,
	
	/** 
	 * Property: withZoomIn
	 * {Boolean} Indica se il pulsante "ZoomIn" deve essere presente.
	 */
	withZoomIn: true,

	/** 
	 * Property: withZoomOut
	 * {Boolean} Indica se il pulsante "ZoomOut" deve essere presente.
	 */
	withZoomOut: true,
	
	/** 
	 * Property: withZoomBoox
	 * {Boolean} Indica se il pulsante "withZoomBoox" deve essere presente.
	 */
	withZoomBox: true,

	/** 
	 * Property: withZoomAll
	 * {Boolean} Indica se il pulsante "ZoomAll" deve essere presente.
	 */
	withZoomAll: true,

	/** 
	 * Property: withMeasure
	 * {Boolean} Indica se il pulsante "Measure" deve essere presente.
	 */
	withMeasure: true,

	/** 
	 * Property: withPrint
	 * {Boolean} Indica se il pulsante "Print" deve essere presente.
	 */
	withPrint: true,

	/** 
	 * Property: withLegenda
	 * {Boolean} Indica se il pulsante "Legenda" deve essere presente.
	 */
	withLegenda: true,

	/** 
	 * Property: withQuery
	 * {Boolean} Indica se il pulsante "Query" deve essere presente.
	 */
	withQuery: true,

	/** 
	 * Property: withSeleziona
	 * {Boolean} Indica se il pulsante "Seleziona" deve essere presente.
	 */
	withSeleziona: true,
	
	/** 
	 * Property: withInfoSeleziona
	 * {Boolean} Indica se il pulsante "Seleziona" deve aver le info sui tasti funzione.
	 */
	withInfoSelezione: true,

	/** 
	 * Property: withAnnullaSeleziona
	 * {Boolean} Indica se il pulsante "AnnullaSeleziona" deve essere presente.
	 */
	withAnnullaSeleziona: true,

	/** 
	 * Property: withLayerList
	 * {Boolean} Indica se il pulsante "LayerList" deve essere presente.
	 */
	withLayerList: true,

	/** 
	 * Property: withIdentify
	 * {Boolean} Indica se il pulsante "Identify" deve essere presente.
	 */
	withIdentify: true,

	/** 
	 * Property: withNuovo
	 * {Boolean} Indica se il pulsante "Nuovo" deve essere presente.
	 */
	withNuovo: true,
	
	/** 
	 * Property: withNuovoDaLayer
	 * {Boolean} Indica se il pulsante "Nuovo da layer" deve essere presente.
	 */
	withNuovoDaLayer: true,
	
	/** 
	 * Property: withNuovoDaImport
	 * {Boolean} Indica se il pulsante "Nuovo da import" deve essere presente.
	 */
	withNuovoDaImport: true,

	/** 
	 * Property: withUpdateAlfa
	 * {Boolean} Indica se il pulsante "UpdateAlfa" deve essere presente.
	 */
	withUpdateAlfa: true,

	/** 
	 * Property: withAdd
	 * {Boolean} Indica se il pulsante "Add" deve essere presente.
	 */
	withAdd: true,

	/** 
	 * Property: withSubtract
	 * {Boolean} Indica se il pulsante "Subtract" deve essere presente.
	 */
	withSubtract: true,

	/** 
	 * Property: withAddSub
	 * {Boolean} Indica se il pulsante "AddSub" deve essere presente.
	 */
	withAddSub: true,

	/** 
	 * Property: withVertexEdit
	 * {Boolean} Indica se il pulsante "VertexEdit" deve essere presente.
	 */
	withVertexEdit: true,

	/** 
	 * Property: withDragDrop
	 * {Boolean} Indica se il pulsante "DragDrop" deve essere presente.
	 */
	withDragDrop: true,

	/** 
	 * Property: withDelete
	 * {Boolean} Indica se il pulsante "Delete" deve essere presente.
	 */
	withDelete: true,

	/** 
	 * Property: withAutoIdentify
	 * {Boolean} Indica se il pulsante "AutoIdentify" deve essere presente.
	 */
	withAutoIdentify: true,
	
	/** 
	 * Property: withFilter
	 * {Boolean} Indica se il pulsante "filter" deve essere presente.
	 */
	withTemporalFilter: true,
	
	/** 
	 * Property: withTimeMachine
	 * {Boolean} Indica se il pulsante della macchina temporale deve essere presente.
	 */
	withTimeMachine: true,
	
	/** 
	 * Property: withSnap
	 * {Boolean} Indica se il pulsante "snap" deve essere presente.
	 */
	withSnap: true,
	
	/** 
	 * Property: withCsw
	 * {Boolean} Indica se il pulsante "csw" deve essere presente.
	 */
	withCsw: true,
	
	/** 
	 * Property: withWMSExporer
	 * {Boolean} Indica se il pulsante "WMSExplorer" deve essere presente.
	 */
	withWMSExporer: true,
	
	/** 
	 * Property: with3D
	 * {Boolean} Indica se il pulsante "3D" deve essere presente.
	 */
	with3D: true,
	
	/** 
	 * Property: withShowCoordinate
	 * {Boolean} Indica se il pulsante "Mostra Cooordinate" deve essere presente.
	 */
	//withShowCoordinate: true,
	
	/** 
	 * Property: temporalFilterWindow
	 */
	temporalFilterWindow: null,

	/** 
	 * Property: buttons
	 * {Array} Array contenente i controllo (button od altro) presenti nella pulsantiera.
	 */
	buttons: null,

	/** 
	 * Property: btnMeasure
	 * 
	 */
	btnMeasure: null,

	/** 
	 * Property: iconBasePath
	 * 
	 */
	iconBasePath:null,  

	/** 
	 * Property: cmbLayerSel
	 * 
	 */
	cmbLayerSel: null, 

	/** 
	 * Property: groupPrefix
	 * 
	 */
	groupPrefix: null, 

	/**
	 * Method: withSearchLayerFilter
	 * 
	 * Parameters:
	 * record - il record.
	 * id - l'identificativo.
	 */
	withSearchLayerFilter: function(record,id){
		return record.data.eventiLayer.raw.interactable;
	},

	/**
	 * Constructor: TolomeoExt.ToloButtonPanelExt
	 * Create a new button toolbar
	 *
	 * Returns:
	 * {<TolomeoExt.ToloButtonPanelExt>} A new button toolbar
	 */
	initComponent: function() {

		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		this.groupPrefix = this.getId();

		this.buttons = new Array();
		
		this.callParent();

		Ext.QuickTips.init();

		// add custom events
		this.addEvents('onPanPressFn');
		this.addEvents('onPanReleaseFn');
		this.addEvents('onCustomButtonPressFn');
		this.addEvents('onCustomButtonDefaultReleaseFn');

		this.addEvents('onNuovoPressFn');
		this.addEvents('onNuovoReleaseFn');
		
		this.addEvents('onNuovoDaLayerPressFn');
		this.addEvents('onNuovoDaLayerReleaseFn');

		this.addEvents('onNuovoDaImportPressFn');
		this.addEvents('onNuovoDaImportReleaseFn');
		
		this.addEvents('onPanNordPressFn');
		this.addEvents('onPanEstPressFn');
		this.addEvents('onPanSudPressFn');
		this.addEvents('onPanOvestPressFn');

		this.addEvents('onHistoryNextPressFn');
		this.addEvents('onHistoryPrevPressFn');
		
		this.addEvents('onZoomInPressFn');
		this.addEvents('onZoomOutPressFn');
		this.addEvents('onZoomBoxPressFn');
		this.addEvents('onZoomAllPressFn');

		this.addEvents('onMeasureActivate');
		this.addEvents('onMeasureDeactivate');
		this.addEvents('onMeasureTypeChange');

		this.addEvents('onPrintPressFn');
		this.addEvents('onLegendPressFn');
		this.addEvents('onLegendReleaseFn');
		this.addEvents('onQueryPressFn');
		this.addEvents('onQueryReleaseFn');
		this.addEvents('onSelectPressFn');
		this.addEvents('onSelectReleaseFn');
		this.addEvents('onIdentifyPressFn');

		this.addEvents('onDeletePressFn');
		this.addEvents('onUpdateAlfaPressFn');
		this.addEvents('onAddPressFn');

		this.addEvents('onAddReleaseFn');
		this.addEvents('onSubtractPressFn');
		this.addEvents('onSubtractReleaseFn');
		this.addEvents('onAddSubPressFn');
		this.addEvents('onAddSubReleaseFn');
		this.addEvents('onVertexEditPressFn');
		this.addEvents('onVertexEditReleaseFn');
		this.addEvents('onDragDropPressFn');

		this.addEvents('onDragDropReleaseFn');
		this.addEvents('onAnnullaSelezioniPressFn');
		this.addEvents('onAutoIdentifyPressFn');
		this.addEvents('onAutoIdentifyReleaseFn');
		
		this.addEvents('onTemporalFilterPressFn');
		this.addEvents('onTemporalFilterReleaseFn');
		this.addEvents('onTemporalFilterApply');
		
		this.addEvents('onTimeMachinePressFn');
		this.addEvents('onTimeMachineReleaseFn');
		
		this.addEvents('onCswPressFn');
		this.addEvents('onCswReleaseFn');
		
		this.addEvents('onWMSPressFn');
		this.addEvents('onWMSReleaseFn');
		
		this.addEvents('showPermalinkClicked');
		this.addEvents('exportForQgisClicked');
		this.addEvents('showInfoClicked');
		this.addEvents('regeneratePageClicked');
		this.addEvents('mailToAdministratorClicked');
		this.addEvents('showGuideClicked');
		this.addEvents('showFaqClicked');
		
		this.addEvents('showWithOSMClicked');
		this.addEvents('showWithGoogleSatelliteClassicClicked');
		this.addEvents('showWithGoogleMapClassicClicked');
		this.addEvents('showWithGoogleSatelliteClicked');
		this.addEvents('showWithGoogleMapClicked');
		this.addEvents('showWithBingObClicked');
		this.addEvents('showWithBingSatelliteClicked');
		this.addEvents('showWithBingMapClicked');
		this.addEvents('showWithHereSatelliteClicked');
		this.addEvents('showWithHereMapClicked');
		
		//this.addEvents('onCoordinatePressFn');
		//this.addEvents('onCoordinateReleaseFn');	
		
		this.addEvents({
			onSnapPressFn  : true,
			onSnapReleaseFn: true
		});

		var thisToolbar = this;
		var layout = this.paramsJS.layOut;

		/*
	    var btnModel = Ext.extend(Ext.Button, {
	    	enableToggle:true,
	    	listeners: { toggle: { fn: this.btnToggleHandler, scope: thisToolbar}}
	    });
		 */

		var listenersToggle = {toggle: {fn: this.btnToggleHandler, scope: thisToolbar}};
		var listenersClick  = {click:  {fn: this.btnClickHandler,  scope: thisToolbar}};
		//var listenersCheck  = { check: { fn: this.btnClickHandler, scope: thisToolbar}};

		var btnSplitModel = Ext.extend(Ext.SplitButton, {
			enableToggle:false,
			scale: (this.defaults && this.defaults.scale) ? this.defaults.scale : undefined,
			defaults: (this.defaults) ? this.defaults : undefined,
			listeners: {toggle: {fn: this.btnToggleHandler, scope: thisToolbar}}
		});

		if (this.iconBasePath==null) this.iconBasePath =  TolomeoExt.Vars.TOLOMEOServer + TolomeoExt.Vars.TOLOMEOStaticRoot + 'img/icone/16-default/'; // this.TOLOMEOServer + '/img/icone/16-default/';
		
		var keymap = new Ext.KeyMap(document, null);

		// Pan
		if (this.withPan) { 
			this.btnPan = this.addButton({
				//scale: 'medium',
				icon: this.iconBasePath + 'hand.gif',
				enableToggle: true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnPan.overflowText"),
				pressed:true,
				allowDepress: false,
				toggleGroup: this.encodeToggleGroup(2),
				becomeDefault: true,
				groupDefault: true,				
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnPan.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnPan.tooltip.title")
					},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Pan',
				opCode: TolomeoExt.ToloAPIOpCodes.btnPan
			});
			keymap.addBinding({
				    key: Ext.EventObject.A,
				    fn: function(key){
				    	if(!this.btnPan.pressed){
							this.btnPan.toggle(true);
				    	}
					},
					alt: true,
					ctrl: true,
				    scope: this,
				    stopEvent: true
				});
		}
		
		// Pan con frecce
		if (this.withPanArrows) { 
			// Pan Nord
			this.addButton({
				icon: this.iconBasePath + 'su.gif',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnPanN.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnPanN.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnPanN.tooltip.title")
					},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'PanNord',
				opCode: TolomeoExt.ToloAPIOpCodes.btnPanNord
			});

			// Pan Sud
			this.addButton({
				icon: this.iconBasePath + 'giu.gif',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'PanSud',
				opCode: TolomeoExt.ToloAPIOpCodes.btnPanSud
			});

			// Pan Ovest
			this.addButton({
				icon: this.iconBasePath + 'sinistra.gif',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'PanOvest',
				opCode: TolomeoExt.ToloAPIOpCodes.btnPanOvest
			});

			// Pan Est
			this.addButton({
				icon: this.iconBasePath + 'destra.gif',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnPanS.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'PanEst',
				opCode: TolomeoExt.ToloAPIOpCodes.btnPanEst
			});
		}
		
		if (this.withNavHistory) {
			// History prev
			this.addButton({
				icon: this.iconBasePath + 'zoom_backward.png',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnNavHistPrev.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnNavHistPrev.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnNavHistPrev.tooltip.title")
				},
				listeners: listenersClick,
				id: this.getId() + 'HistoryPrevBtn',
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'HistoryPrev',
				opCode: TolomeoExt.ToloAPIOpCodes.btnHistoryPrev,
				disabled: true
			});
			
			// History next
			this.addButton({
				icon: this.iconBasePath + 'zoom_forward.png',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnNavHistNext.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnNavHistNext.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnNavHistNext.tooltip.title")
				},
				listeners: listenersClick,
				id: this.getId() + 'HistoryNextBtn',
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'HistoryNext',
				opCode: TolomeoExt.ToloAPIOpCodes.btnHistoryNext,
				disabled: true
			});			
		}
		
		
		this.add('-');
		
		// ZoomIn
		if (this.withZoomIn) {
			this.addButton({
				icon: this.iconBasePath + 'zoomin.gif',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomIn.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomIn.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomIn.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'ZoomIn',
				opCode: TolomeoExt.ToloAPIOpCodes.btnZoomIn
			});
		}

		// ZoomOut
		if (this.withZoomOut) {
			this.addButton({
				icon: this.iconBasePath + 'zoomout.gif',
				enableToggle:false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomOut.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomOut.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomOut.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'ZoomOut',
				opCode: TolomeoExt.ToloAPIOpCodes.btnZoomOut
			});
		}
		
		// ZoomBoox
		if (this.withZoomBox) {
			this.addButton({
				icon: this.iconBasePath + 'zoombox.gif',
				enableToggle: true,
				allowDepress: false,
				toggleGroup: this.encodeToggleGroup(2),
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomBox.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomBox.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomBox.tooltip.title")
				},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'ZoomBox',
				opCode: TolomeoExt.ToloAPIOpCodes.btnZoomBox
			});
		}

		// ZoomAll
		if (this.withZoomAll) {
			this.addButton({
				icon: this.iconBasePath + 'nozoom.gif',
				enableToggle:false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomAll.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomAll.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnZoomAll.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'ZoomAll',
				opCode: TolomeoExt.ToloAPIOpCodes.btnZoomAll
			});
		}
		
		if (this.withZoomIn || this.withZoomOut || this.withZoomAll) this.add('-');
		
		/*
		Ext.define('btnSplitModel', {
			extend: 'Ext.SplitButton',
			scale: (this.defaults && this.defaults.scale) ? this.defaults.scale : undefined,
			defaults: (this.defaults) ? this.defaults : undefined,
			listeners: {toggle: {fn: this.btnToggleHandler, scope: thisToolbar}}
		});
		*/
		
		// Measure
		if (this.withMeasure) {
			this.btnMeasure = this.addButton(
					new btnSplitModel({
						icon: this.iconBasePath + 'misura.gif',
						enableToggle: true,
						allowDepress: false,
						toggleGroup: this.encodeToggleGroup(2),
						overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasure.overflowText"),
						tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasure.tooltip.text"), 
							title: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasure.tooltip.title")
						},
						scale: (this.defaults && this.defaults.scale) ? this.defaults.scale : "small",
						// Proprietà aggiuntive per Tolomeo
						listeners: { toggle: {fn: this.btnMeasureMng , scope: thisToolbar} },
						handlerBaseName: 'Measure',
						menu: {
							cls: 'clearCSS',
							
						
							items: [{
								text: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasurePoly.Text"),
								checked: false,
								iconCls : 'iconPolygonalMeasure',
								cls : "clearCss",
								group: 2,
								overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasurePoly.overflowText"),
								tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasurePoly.tooltip.text"), 
									title: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasurePoly.tooltip.title")
								},
								listeners: { checkchange: {fn: this.btnMeasureItemMng, scope: thisToolbar} },
								// Proprietà aggiuntive per Tolomeo
								handlerBaseName: 'MeasurePolygon',
								measureType: 0,
								opCode: TolomeoExt.ToloAPIOpCodes.btnMeasure
							},{
								text: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasureCircle.Text"),
								checked: false,
								iconCls : 'iconCircularMeasure',
								cls : "clearCss",
								group: 2,
								overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasureCircle.overflowText"),
								tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasureCircle.tooltip.text"), 
									title: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasureCircle.tooltip.title")
								},
								listeners: { checkchange: {fn: this.btnMeasureItemMng , scope: thisToolbar} },
								// Proprietà aggiuntive per Tolomeo
								handlerBaseName: 'MeasureCircle',
								measureType: 1,
								opCode: TolomeoExt.ToloAPIOpCodes.btnMeasure
							},{
								text: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasureLine.Text"),
								checked: true,
								iconCls : 'iconLinearMeasure',
								cls : "clearCss",
								group: 2,
								overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasureLine.overflowText"),
								tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasureLine.tooltip.text"), 
									title: ToloI18n.getMsg("ToloButtonPanelExt.btnMeasureLine.tooltip.title")
								},
								listeners: { checkchange: {fn: this.btnMeasureItemMng , scope: thisToolbar} },
								// Proprietà aggiuntive per Tolomeo
								handlerBaseName: 'MeasureLine',
								measureType: 2,
								opCode: TolomeoExt.ToloAPIOpCodes.btnMeasure
							}]
						}
					})
			);
			this.add('-');
		}
		
		// TimeMachine
		// TODO  generalizzare adesso considera solo mappa[0] gestisce solo prima mappa
		if (this.withTimeMachine && (this.paramsJS.mappe.mappaList[0].timeMachineList!=null && this.paramsJS.mappe.mappaList[0].timeMachineList.length>0)) {
			this.addButton({
				icon: this.iconBasePath + 'macchinaTempo.png',
				enableToggle: true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnTimeMachine.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnTimeMachine.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnTimeMachine.tooltip.title")
				},
				listeners: listenersToggle,
				toggleGroup: this.encodeToggleGroup(0),
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'TimeMachine',
				opCode: TolomeoExt.ToloAPIOpCodes.btnTimeMachine
			});
			this.add('-');
		}

		// Print
		if (this.withPrint) {
			this.addButton({
				icon: this.iconBasePath + 'print.gif',
				enableToggle:false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnPrint.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnPrint.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnPrint.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Print',
				opCode: TolomeoExt.ToloAPIOpCodes.btnPrint
			});
		}

		// Legenda
		if (this.withLegenda) {
			if (this.paramsJS.mappe.mappaList[0].legenda!=null) {
				this.addButton({
					icon: this.iconBasePath + 'legenda.gif',
					enableToggle: true,
					toggleGroup: this.encodeToggleGroup(1),
					overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnLegenda.overflowText"),
					tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnLegenda.tooltip.text"), 
						title: ToloI18n.getMsg("ToloButtonPanelExt.btnLegenda.tooltip.title")
					},
					listeners: listenersToggle,
					// Proprietà aggiuntive per Tolomeo
					handlerBaseName: 'Legend',
					opCode: TolomeoExt.ToloAPIOpCodes.btnLegenda
				});
			}
		}

		// verifica la necessità di pannello query
		if (this.withQuery) {
			var bQuery = false;
			for (var i=0; i<this.paramsJS.azioniEventi.eventiLayerList.length; i++) {
				if (this.paramsJS.azioniEventi.eventiLayerList[i].azioniEventiRicercaList.ricercaList.length != 0){
					bQuery = true; 
					break;
				}
			}
			if (bQuery) {
				this.addButton({
					icon: this.iconBasePath + 'ricerca.gif',
					enableToggle: true,
					toggleGroup: this.encodeToggleGroup(1),
					overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnCerca.overflowText"),
					tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnCerca.tooltip.text"), 
						title: ToloI18n.getMsg("ToloButtonPanelExt.btnCerca.tooltip.title")
					},
					listeners: listenersToggle,
					// Proprietà aggiuntive per Tolomeo
					handlerBaseName: 'Query',
					opCode: TolomeoExt.ToloAPIOpCodes.btnRicerca
				});
			}
		}

		if (this.withPrint || this.withLegenda || this.withQuery) this.add('-');
		
		// Seleziona
		if (this.withSeleziona) {
			
			var helpMsg = ToloI18n.getMsg("ToloButtonPanelExt.btnSelect.m1");
			if (this.withInfoSelezione) {
				helpMsg += ToloI18n.getMsg("ToloButtonPanelExt.btnSelect.m2");
				if (this.paramsJS.selectDefaultMode=='FIRSTONTOP') {
					helpMsg += ToloI18n.getMsg("ToloButtonPanelExt.btnSelect.m3"); 
				} else {
					helpMsg += ToloI18n.getMsg("ToloButtonPanelExt.btnSelect.m4");  
				}
				helpMsg += ToloI18n.getMsg("ToloButtonPanelExt.btnSelect.m5");
				
			}
			
			
			
			ToloI18n.getMsg("ToloButtonPanelExt.btnCerca.overflowText"),
			
			this.btnSelect = this.addButton({
				icon: this.iconBasePath + 'sector.gif',
				enableToggle:true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnSelect.overflowtext"),
				toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				tooltip: {text: helpMsg, title:ToloI18n.getMsg("ToloButtonPanelExt.btnSelect.title")},
				listeners: listenersToggle,
				becomeDefault: true,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Select',
				opCode: TolomeoExt.ToloAPIOpCodes.btnSeleziona
			});
			
			if(this.paramsJS.getSelectableCodTPN().length>0){
				keymap.addBinding({
					    key: Ext.EventObject.S,
					    fn: function(key){
					    	if(!this.btnSelect.disabled && !this.btnSelect.pressed){
								this.btnSelect.toggle(true);
					    	}
						},
						alt: true,
						ctrl: true,
					    scope: this,
					    stopEvent: true
					});
			}
		}
		
		// Annulla selezioni
		if (this.withAnnullaSeleziona) {
			this.addButton({
				icon: this.iconBasePath + 'unsector.gif',
				enableToggle:false,
				toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnAnnullaSeleziona.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnAnnullaSeleziona.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnAnnullaSeleziona.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'AnnullaSelezioni',
				opCode: TolomeoExt.ToloAPIOpCodes.btnAnnullaSelezioni
			});
			
		}
		
		if ( this.withSeleziona || this.withAnnullaSeleziona ) this.add('-');
		//if (this.withLayerList || this.withNuovo || this.withUpdateAlfa || this.withAdd || this.withSubtract || this.withAddSub || this.withVertexEdit || this.withDragDrop || this.withDelete ) this.add('Editing :  ');

		// Layer list
		if (this.withLayerList) {
			
			
			var layerStore = new Ext.data.JsonStore({
				proxy: {
		    		type: 'memory'//,
		    		// reader configs
		    		//reader: {
		    		//	type: 'json',
		    		//	root: 'valori',
		    		//	idProperty: suggestProvider[i].valueFieldName // 'COD',
		    			//fields: fields //['COD', 'DESC', 'REG']
					//}
				},
				
				mode: "local",
				data: this.paramsJS.azioniEventi.eventiLayerList,
				autoLoad: false,
				remoteSort: false,
				fields: [{
						name: 'descrizioneLayer',
						mapping: 'descrizioneLayer'
					},{
						name: 'codTPN',
						mapping: 'codTPN'
					},{
						name: 'eventiLayer',
					    convert: function (v, rec) { return rec; }
					}]
			});
			
			/*
			var layerStore = new Ext.data.JsonStore({
				fields: [{
					name: 'descrizioneLayer',
					mapping: 'descrizioneLayer'
				},{
					name: 'codTPN',
					mapping: 'codTPN'
				},{
					name: 'eventiLayer',
				    convert: function (v, rec) { return rec; }
				}],
				proxy: {
					
				}
				data : this.paramsJS.azioniEventi.eventiLayerList
			});*/

			layerStore.filterBy(this.withSearchLayerFilter);

			this.cmbLayerSel = new Ext.form.ComboBox({
				typeAhead: true,
				queryMode: 'local',
				triggerAction: 'all',
				forceSelection: true,
				editable: false,
				allowBlank: false,
				emptyText: ToloI18n.getMsg("ToloButtonPanelExt.cmbLayerSel.emptyText"),
				selectOnFocus:true,
				hiddenName: 'codTPN',
				valueField: 'codTPN',
				displayField: 'descrizioneLayer',
				name: 'codTPN1',
				lastQuery: '',
				listeners: {select: {fn: this.cmbSelectLayerHandler, scope: thisToolbar},
				beforerender: function(){this.store.filterBy(function(record,id){
					return record.data.eventiLayer.raw.interactable;
				},this);}},
				store: layerStore,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: null
				//TODO opCode: TolomeoExt.ToloAPIOpCodes.btnPan
			});				

			// Se esiste seleziono prima scelta
			if (layerStore.getCount()>1) {
				this.cmbLayerSel.setValue(layerStore.getRange(0,0)[0].data.codTPN);
			} else if (layerStore.getCount()==1) {
				this.cmbLayerSel.setVisible(false);
				this.cmbLayerSel.setValue(layerStore.getRange(0,0)[0].data.codTPN);
			} else if (layerStore.getCount()<1) {
				this.cmbLayerSel.setVisible(false);
			}

			this.addCombo(this.cmbLayerSel);
		}    		

		// Visualizza informazioni su oggetto		
		if (this.withIdentify) {
			// Identify
			this.addButton({
				icon: this.iconBasePath + 'info.gif',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnIdentify.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnIdentify.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnIdentify.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Identify',
				opCode: TolomeoExt.ToloAPIOpCodes.btnIdentify
			});
		}						

		// Nuovo
		if (this.withNuovo) {
			/*
			this.addButton({
				icon: this.iconBasePath +  'nuovo.gif',
				enableToggle: true,
				overflowText: "Nuovo oggetto",
				toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				tooltip: {text: 'Crea un nuovo oggetto cartografico nella mappa (punto, linea, poligono, ecc...)', title:'Nuovo oggetto'},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Nuovo',
				opCode: TolomeoExt.ToloAPIOpCodes.btnNuovo
			});
			*/
			
			this.btnNew = this.addButton(
					new btnSplitModel({
						enableToggle: true,
						icon: this.iconBasePath + 'nuovo.gif',
						allowDepress: false,
						toggleGroup: this.encodeToggleGroup(2),
						overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnNew.overflowText"),
						tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnNew.tooltip.text"), 
							title: ToloI18n.getMsg("ToloButtonPanelExt.btnNew.tooltip.title")
						},
						//listeners: listenersToggle,
						listeners: { toggle: {fn: this.btnNewToggleHandler , scope: thisToolbar} },
						scale: (this.defaults && this.defaults.scale) ? this.defaults.scale : "small",
						// Proprietà aggiuntive per Tolomeo
						//listeners: { toggle: {fn: this.btnMeasureMng , scope: thisToolbar} },
						handlerBaseName: 'Nuovo',
						opCode: TolomeoExt.ToloAPIOpCodes.btnNuovo,
						newType: 0,
						menu: {
							cls: 'clearCSS',
							items: [{
								text: 'Nuovo',
								checked: true,
								icon: this.iconBasePath + 'nuovo.gif',
								group: 2,
								overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnNewAMano.overflowText"),
								tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnNewAMano.tooltip.text"), 
									title: ToloI18n.getMsg("ToloButtonPanelExt.btnNewAMano.tooltip.title")
								},
								listeners: { checkchange: {fn: this.btnNewItemMng, scope: thisToolbar} },
								toggleGroup: this.encodeToggleGroup(2),
								// Proprietà aggiuntive per Tolomeo
								//handlerBaseName: 'Nuovo',
								newType: 0
								//opCode: TolomeoExt.ToloAPIOpCodes.btnNuovo
							},{
								text: 'Nuovo con CAD',
								checked: false,
								icon: this.iconBasePath + 'nuovoByCAD.gif',
								group: 2,
								overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnNewCAD.overflowText"),
								tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnNewCAD.tooltip.text"), 
									title: ToloI18n.getMsg("ToloButtonPanelExt.btnNewCAD.tooltip.title")
								},
								listeners: { checkchange: {fn: this.btnNewItemMng , scope: thisToolbar} },
								toggleGroup: this.encodeToggleGroup(2),
								// Proprietà aggiuntive per Tolomeo
								//handlerBaseName: 'Nuovo',
								newType: 1
								//opCode: TolomeoExt.ToloAPIOpCodes.btnNuovo
							}]
						}
					})
			);
			
		}

		// NuovoDaLayer
		if (this.withNuovoDaLayer) {
			
			this.addButton({
				icon: this.iconBasePath +  'aggiungiOggetto2.png',
				enableToggle: false,
				//toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnNuovoDaLayer.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnNuovoDaLayer.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnNuovoDaLayer.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'NuovoDaLayer',
				opCode: TolomeoExt.ToloAPIOpCodes.btnNuovoDaLayer
			});
			
		}

		// NuovoDaImport
		if (this.withNuovoDaImport) {
			
			this.addButton({
				icon: this.iconBasePath +  'application_get.png',
				enableToggle: false,
				//toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnNuovoDaImport.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnNuovoDaImport.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnNuovoDaImport.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'NuovoDaImport',
				opCode: TolomeoExt.ToloAPIOpCodes.btnNuovoDaImport
			});
			
		}
		
		// UpdateAlfa
		if (this.withUpdateAlfa) {
			this.addButton({
				icon: this.iconBasePath + 'modifica.gif',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnUpdateAlpha.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnUpdateAlpha.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnUpdateAlpha.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'UpdateAlfa',
				opCode: TolomeoExt.ToloAPIOpCodes.btnUpdateAlfa
			});
		}

		// Add
		if (this.withAdd) {
			this.addButton({
				icon: this.iconBasePath + 'poligono.gif',
				enableToggle: true,
				toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnAdd.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnAdd.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnAdd.tooltip.title")
				},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Add',
				opCode: TolomeoExt.ToloAPIOpCodes.btnAdd
			});
		}

		// Subtract
		if (this.withSubtract) {
			this.addButton({
				icon: this.iconBasePath + 'poligonodelete.gif',
				enableToggle: true,
				toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnSubtract.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnSubtract.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnSubtract.tooltip.title")
				},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Subtract',
				opCode: TolomeoExt.ToloAPIOpCodes.btnSubtract
			});	
		}

		// AddSub
		if (this.withAddSub) {
			this.addButton({
				icon: this.iconBasePath + 'poligonopiumeno.gif',
				enableToggle: true,
				toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnAddSub.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnAddSub.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnAddSub.tooltip.title")
				},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'AddSub',
				opCode: TolomeoExt.ToloAPIOpCodes.btnAddSub
			});	
		}

		// VertexEdit
		if (this.withVertexEdit) {
			this.addButton({
				icon: this.iconBasePath + 'poligonovertici.gif',
				enableToggle: true,
				toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnVertexEdit.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnVertexEdit.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnVertexEdit.tooltip.title")
				},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'VertexEdit',
				opCode: TolomeoExt.ToloAPIOpCodes.btnVertexEdit
			});	
		}

		// DragDrop
		if (this.withDragDrop) {
			this.addButton({
				icon: this.iconBasePath + 'hand.gif',
				enableToggle: true,
				toggleGroup: this.encodeToggleGroup(2),
				allowDepress: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnDragDrop.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnDragDrop.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnDragDrop.tooltip.title")
				},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'DragDrop',
				opCode: TolomeoExt.ToloAPIOpCodes.btnDragDrop
			});	
		}

		// Delete
		if (this.withDelete) {
			this.addButton({
				icon: this.iconBasePath + 'elimina.gif',
				enableToggle: false,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnDelete.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnDelete.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnDelete.tooltip.title")
				},
				listeners: listenersClick,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Delete',
				opCode: TolomeoExt.ToloAPIOpCodes.btnDelete
			});	
		}
		
		var isSnappingRequired = false; 
		// Controllo se c'è qualche snapping impostato per l'applicazione
		for(var evtLi = 0; evtLi < this.paramsJS.azioniEventi.eventiLayerList.length; evtLi++){			
			var evtL = this.paramsJS.azioniEventi.eventiLayerList[evtLi];			
			if(evtL.snapping && evtL.snapping.snappingLayerList && evtL.snapping.snappingLayerList.length > 0){
				isSnappingRequired = true;
				break;
			}
		}
		
		// Snap
		if(isSnappingRequired && this.withSnap) {
			this.addButton({
				icon: this.iconBasePath + 'grid-snap-dot.png',
				enableToggle: true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnSnap.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnSnap.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnSnap.tooltip.title")
				},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'Snap',
				opCode: TolomeoExt.ToloAPIOpCodes.btnSnap
			});		
		}
		
		// Csw
		if(layout.csw && this.withCsw) {
			this.addButton({
				icon: this.iconBasePath + 'csw.png',
				enableToggle: true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnCsw.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnCsw.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnCsw.tooltip.title")
				},
				listeners: listenersToggle,
				handlerBaseName: 'Csw',
				opCode: TolomeoExt.ToloAPIOpCodes.btnCsw
			});		
		}
		
		// WMS
		if(layout.WMSExplorer && this.withWMSExporer) {
			this.addButton({
				icon: this.iconBasePath + 'wms.png',
				enableToggle: true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnWMSExplorer.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnWMSExplorer.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnWMSExplorer.tooltip.title")
				},
				listeners: listenersToggle,
				handlerBaseName: 'WMS',
				opCode: TolomeoExt.ToloAPIOpCodes.btnWMSExplorer
			});		
		}

		// 3D
		if(layout.visualizzazione3D && this.with3D && Modernizr.webgl) {
			this.addButton({
				icon: this.iconBasePath + '3d_glasses.png',
				enableToggle: true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btn3D.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btn3D.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btn3D.tooltip.title")
				},
				listeners: listenersToggle,
				handlerBaseName: '3D',
				opCode: TolomeoExt.ToloAPIOpCodes.btn3D
			});		
		}

		// Filtro temporale
		if (layout.conFiltroTemporale && this.withTemporalFilter) {
			this.addButton({
		    	icon: this.iconBasePath + 'filtro.gif',
		    	//enableToggle: true,
		    	//toggleGroup: this.encodeToggleGroup(2),
				allowDepress: true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnFiltroTemporale.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnFiltroTemporale.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnFiltroTemporale.tooltip.title")
				},
		    	listeners: listenersClick,
		    	// Proprietà aggiuntive per Tolomeo
		    	handlerBaseName: 'TemporalFilter',
		    	opCode: TolomeoExt.ToloAPIOpCodes.btnTemporalFilter
		    });
		}
		
		// AutoIdentify
		if (this.withAutoIdentify && this.autoIdentifyLayersPresent()) {
			this.addButton({
				icon: this.iconBasePath +  'identifica.gif',
				enableToggle: true,
				allowDepress: true,
				overflowText: ToloI18n.getMsg("ToloButtonPanelExt.btnAutoIdentify.overflowText"),
				tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnAutoIdentify.tooltip.text"), 
					title: ToloI18n.getMsg("ToloButtonPanelExt.btnAutoIdentify.tooltip.title")
				},
				listeners: listenersToggle,
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'AutoIdentify',
				opCode: TolomeoExt.ToloAPIOpCodes.btnAutoIdentify
			});
		}

		// Custom buttons
		for (var i=0; i<layout.customButtonList.length; i++) {
			var cb = layout.customButtonList[i];
			var btNo = TolomeoExt.ToloAPIOpCodes.btnCustomBase+i;

			this.addButton({
				icon: this.iconBasePath + cb.iconFileName,
				enableToggle: (cb.gruppo!=null && cb.gruppo!=-1 ) ? true : false,
				listeners:    (cb.gruppo!=null && cb.gruppo!=-1 ) ? listenersToggle : listenersClick,
				toggleGroup:  (cb.gruppo!=null && cb.gruppo!=-1 ) ? this.encodeToggleGroup(cb.gruppo) : null,
				overflowText: cb.iconTitleMessage,
				//allowDepress: true,
				tooltip: { text: cb.tooltipMessage, title:cb.iconTitleMessage},
				// Proprietà aggiuntive per Tolomeo
				handlerBaseName: 'CustomButton',
				opCode: btNo,
				idCustomButton: cb.idCustomButton,
				pressFunction: cb.pressFunction,
				releaseFunction: cb.releaseFunction
			});

			//bottoni.add(btNo, 'customButton' + btNo, cb.iconFileName, cb.gruppo, pf, rf, cb.disabledMessage, cb.iconTitleMessage, cb.iconAltMessage, cb.idCustomButton);		
		}

		/*// Custom buttons
		for (var i=0; i<paramsJS.layOut.customButtonList.length; i++) {
			var cb = paramsJS.layOut.customButtonList[i];
			var btNo = btnCustomBase+i;
			var pf = ((cb.pressFunction == null)||(cb.pressFunction == ''))  ? btnCustomButtonDefaultPressFn : cb.pressFunction;
			var rf = ((cb.releaseFunction == null)||(cb.releaseFunction == ''))  ? btnCustomButtonDefaultReleaseFn : cb.releaseFunction;

			 //<li><a href="JavaScript:bottoni.press(btnIdentify);" title="Ottieni informazioni su un oggetto selezionato"><img src="${applx.urlCss}/img/icone_on/info.gif" alt="Informazioni" id="identify" /></a></li>		

			bottoni.add(btNo, 'customButton' + btNo, cb.iconFileName, cb.gruppo, pf, rf, cb.disabledMessage, cb.iconTitleMessage, cb.iconAltMessage, cb.idCustomButton);		
		}*/
								
		this.filler = new Ext.toolbar.Fill();		
		this.add(this.filler);
		this.fillerAdded = true; 		
        
		this.add('-');		
		
		this.add({
			icon: this.iconBasePath + 'permalink.png',
			id: this.getId() + 'permalinkBtn',
			disabled : true,
			tooltip: {text: ToloI18n.getMsg("ToloButtonPanelExt.btnPermalink.tooltip.text"), 
				title: ToloI18n.getMsg("ToloButtonPanelExt.btnPermalink.tooltip.title")
			},
			listeners: { 								
				click: {
					fn: function() {     	    								
						this.fireEvent('showPermalinkClicked');																												
					},
					scope: this
	    		}
	    		
			}			
		});		
		
		this.add('-');	
		
		if (layout.conExportQGIS || layout.withVisWith) {
			var strumentiItems = [];
			
			
			
			if (layout.withVisWith &&
				(layout.withVisWith.withOSM ||
				 layout.withVisWith.withGoogle ||
				 layout.withVisWith.withBing ||
				 layout.withVisWith.withHere)) { 
				
				var mnuVisualizzaCon = Ext.create('Ext.menu.Item', {
	    			iconCls : 'iconVisCon',
	    			text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.text"),
					menu : {
						cls: 'clearCSS',
						items : []
					}
				});
				strumentiItems.push(mnuVisualizzaCon);
				
				if (layout.withVisWith.withOSM) {
					var mnuOSM = Ext.create('Ext.menu.Item', {
						text : ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.OSM.text"),
						iconCls : 'iconVisConOSM',
						listeners: { 								
							click: {
								fn: function() {     	    								
									this.fireEvent('showWithOSMClicked',null,null);																												
								},
								scope: this
				    		}}
					});
					mnuVisualizzaCon.menu.add(mnuOSM);
				}
				
				if (layout.withVisWith.withGoogle) {
					var mnuGoogle = Ext.create('Ext.menu.Item', {
						text : ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.Google.text"),
		    			iconCls : 'iconVisConGoogle',
						menu : {
							cls: 'clearCSS',
							items: [{
								text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.GoogleSat.text"),
								cls : "clearCss",
								listeners: { 								
									click: {
										fn: function() {     	    								
											this.fireEvent('showWithGoogleSatelliteClicked',null,null);																												
										},
										scope: this
						    		}
								}},{
									text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.GoogleMappa.text"),
									cls : "clearCss",
									listeners: { 								
										click: {
											fn: function() {     	    								
												this.fireEvent('showWithGoogleMapClicked',null,null);																												
											},
											scope: this
							    		}
									}},{
									text:  ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.GoogleSatClassica.text"),
									cls : "clearCss",
									listeners: { 								
										click: {
											fn: function() {     	    								
												this.fireEvent('showWithGoogleSatelliteClassicClicked',null,null);																												
											},
											scope: this
							    		}
									}},{
									text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.GoogleMappaClassica.text"),
									cls : "clearCss",
									listeners: { 								
										click: {
											fn: function() {     	    								
												this.fireEvent('showWithGoogleMapClassicClicked',null,null);																												
											},
											scope: this
							    		}
									}}]
						}
					});
					mnuVisualizzaCon.menu.add(mnuGoogle);
				}
				
				if (layout.withVisWith.withHere) {
					var mnuHere = Ext.create('Ext.menu.Item', {
						text : 'Here',
		    			iconCls : 'iconVisConHere',
						menu : {
							cls: 'clearCSS',
							items: [{
								text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.HereSat.text"),
								cls : "clearCss",
								listeners: { 								
									click: {
										fn: function() {     	    								
											this.fireEvent('showWithHereSatelliteClicked',null,null);																												
										},
										scope: this
						    		}
								}},{
								text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.HereMappa.text"),
								cls : "clearCss",
								listeners: { 								
									click: {
										fn: function() {     	    								
											this.fireEvent('showWithHereMapClicked',null,null);																												
										},
										scope: this
						    		}
								}}]
						}
					});
					mnuVisualizzaCon.menu.add(mnuHere);
				}
				
				if (layout.withVisWith.withBing) {
					var mnuBing = Ext.create('Ext.menu.Item', {
						text : 'Bing',
		    			iconCls : 'iconVisConBing',
						menu : {
							cls: 'clearCSS',
							items: [{
								text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.BingSatOb.text"),
								cls : "clearCss",
								listeners: { 								
									click: {
										fn: function() {     	    								
											this.fireEvent('showWithBingObClicked',null,null);																												
										},
										scope: this
						    		}
								}},{
								text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.BingSat.text"),
								cls : "clearCss",
								listeners: { 								
									click: {
										fn: function() {     	    								
											this.fireEvent('showWithBingSatelliteClicked',null,null);																												
										},
										scope: this
						    		}
								}},{
								text: ToloI18n.getMsg("ToloButtonPanelExt.mnuVisWith.BingMappa.text"),
								cls : "clearCss",
								listeners: { 								
									click: {
										fn: function() {     	    								
											this.fireEvent('showWithBingMapClicked',null,null);																												
										},
										scope: this
						    		}
								}}]
						}
					});
					mnuVisualizzaCon.menu.add(mnuBing);
				}
				
			}
			
			if (layout.conExportQGIS) {
				var mnuEsporta = Ext.create('Ext.menu.Item', {
					text : ToloI18n.getMsg("ToloButtonPanelExt.mnuEsporta.text"),
					menu : {
						cls: 'clearCSS',
						items : [{
								xtype: 'menuitem',
								text: ToloI18n.getMsg("ToloButtonPanelExt.mnuEsporta.qgis.text"),
								iconCls : 'iconExportForQGis',
								id: this.getId() + 'exportQgisBtn',
								disabled : true,
								menu:{
									cls: 'clearCSS',
									items: [
										{
											text: ToloI18n.getMsg("ToloButtonPanelExt.mnuEsporta.qgis180.text"),
					    	    			iconCls : 'iconExportForQGis',
											cls : "clearCss",
											listeners: { 								
												click: {
													fn: function() {     	    								
														this.fireEvent('exportForQgisClicked',null,null, "1.8.0");																												
													},
													scope: this
									    		}
									    		
											}	
										},{
											text: ToloI18n.getMsg("ToloButtonPanelExt.mnuEsporta.qgis2180.text"),
					    	    			iconCls : 'iconExportForQGis',
											cls : "clearCss",
											listeners: { 								
												click: {
													fn: function() {     	    								
														this.fireEvent('exportForQgisClicked',null,null, "2.18.0");																												
													},
													scope: this
									    		}
									    		
											}	
										}
									
									]
								}
							}]
					}
				});
				strumentiItems.push(mnuEsporta);
			}			
			
			this.addButton({
				//text: 'Strumenti',
				icon: this.iconBasePath + 'options.png',
				hidden : true,
				id: this.getId() + 'toolsMenu',
				tooltip : ToloI18n.getMsg("ToloButtonPanelExt.btnStrumenti.tooltip"),
				//scale: 'medium',
				menu : {		
					xtype: 'menu',
					cls: 'clearCSS',
					items: strumentiItems
				}
			});
		}
		
		var troubleItems = [];
		troubleItems.push ({
        	text: ToloI18n.getMsg("ToloButtonPanelExt.mnuTrouble.rigenera.text"),
        	iconCls : 'iconRegenerateWithoutCache',
			cls : "clearCss",
        	tooltip: ToloI18n.getMsg("ToloButtonPanelExt.mnuTrouble.rigenera.tooltip"),
        	listeners : {
        		click : {
        			fn : function(){
        				this.fireEvent('regeneratePageClicked');
        			},
        			scope: this
        		}
        	}     
        });
        
        
        
        if(layout.helpMailTo){        	
        	troubleItems.push ({
            	text: ToloI18n.getMsg("ToloButtonPanelExt.mnuTrouble.mailto.text"),
            	iconCls : 'iconMailToAdmin',
				cls : "clearCss",
				//'Invia una e-mail a ' + layout.helpMailTo,
            	tooltip:  ToloI18n.getMsg("ToloButtonPanelExt.mnuTrouble.mailto.tooltip", {MAIL: layout.helpMailTo}),
            	listeners : {
            		click : {
            			fn : function(){
            				this.fireEvent('mailToAdministratorClicked',layout.helpMailTo,layout.helpMailSubject);
            			},
            			scope: this
            		}
            	}    
            });
        }
        
        var helpItems = [];
        if(layout.helpUrl){
        	
        	helpItems.push({
                	text : ToloI18n.getMsg("ToloButtonPanelExt.mnuGuida.text"),              
                	listeners : {
                		click : {
                			fn : function(){
                				this.fireEvent('showGuideClicked',layout.helpUrl);
                			},
                			scope: this
                		}
                	}    
                });
                
            helpItems.push('-');
                            
        }
        
        if(layout.faqUrl){
        	helpItems.push({
                	text : ToloI18n.getMsg("ToloButtonPanelExt.mnuFAQ.text"),
                	listeners : {
                		click : {
                			fn : function(){
                				this.fireEvent('showFaqClicked',layout.faqUrl);
                			},
                			scope: this
                		}
                	}    
                });
                
            helpItems.push('-');
        }
        
        helpItems.push({
                	text: ToloI18n.getMsg("ToloButtonPanelExt.mnuProblemi.text"),
                	menu: {		   
                		cls: 'clearCSS',
		                items: troubleItems
               		}
                });
                
        helpItems.push('-');
        helpItems.push({
                	text: ToloI18n.getMsg("ToloButtonPanelExt.mnuInfoTolomeo.text"),
                	listeners : {
                		click : {
                			fn : function(){
                				this.fireEvent('showTolomeoInfoClicked');	
                			},
                			scope: this
                		}
                	}                	
                });
                
        if(layout.helpInfo){
        	helpItems.push({
                	text: layout.helpInfo.mainTitle,
                	listeners : {
                		click : {
                			fn : function(){
                				this.fireEvent('showCustomInfoClicked',layout.helpInfo);	
                			},
                			scope: this
                		}
                	}                	
                });
        }
                
		
		this.add({
			tooltip : ToloI18n.getMsg("ToloButtonPanelExt.mnuAiutoEInfo.text"),
			icon: this.iconBasePath + 'help.png',           
            menu: {
            	cls: 'clearCSS',
                xtype: 'menu',
                plain: true,
                items: helpItems
            }
        });

		this.add({
			//tooltip : 'aaaa',
			//icon: this.iconBasePath + 'help.png', 
			//xtype: 'splitbutton',
			icon: this.getLanguageIcon(ToloI18n.getLanguage()),
            menu: {
            	cls: 'clearCSS',
                xtype: 'menu',
                plain: true,
                items: [
                	{
                		xtype: 'menucheckitem',
                		checked: ToloI18n.getLanguage()=='it',
                		icon: this.getLanguageIcon('it'),
                		text: 'Italiano',
                		group: 'lang',
                		enableToggle: true,
                		listeners: { checkchange: {fn: function(button, checked) { 
                									if (checked) button.up('button').setIcon(button.icon);} , scope: thisToolbar},
                					 click: {fn: function() { this.languageChange('it');}, scope: this}
                					}
                	},
                	{
                		checked: ToloI18n.getLanguage()=='en',
                		icon: this.getLanguageIcon('en'),
						group: 'lang',
						enableToggle: true,
                		iconCls : 'iconLangEn',
                		text: 'English',
                		listeners: { checkchange: {fn: function(button, checked) { 
                			if (checked) button.up('button').setIcon(button.icon);} , scope: thisToolbar},
                			click: {fn: function() { this.languageChange('en');}, scope: this}}
                	}
                ]
            }
        });

		
        
		this.doLayout();													

		
		/**
		 * Finestra filtro temporale
		 */
		this.temporalFilterWindow = Ext.create('Ext.Window', {
				title: ToloI18n.getMsg("ToloButtonPanelExt.winFiltroTemp.title"),
				closeAction: 'hide',
				constrain: true,
				width: 300,
				autoHeight: true,
				items: new Ext.FormPanel({
					frame: true,
					border: false,
					autoHeight: true,
					bodyStyle: 'padding-top:5px;',
					defaults: {
						labelWidth: 50,
						anchor: '98%'
					},
					items: [{
						id: this.getId() + 'dtInizio',
						xtype: 'datefield',
						fieldLabel: ToloI18n.getMsg("ToloButtonPanelExt.winFiltroTemp.fldDtInizio"),
						format: 'd/m/Y'
					},{
						id: this.getId() + 'dtFine',
						xtype: 'datefield',
						fieldLabel: ToloI18n.getMsg("ToloButtonPanelExt.winFiltroTemp.fldDtFine"),
						format: 'd/m/Y'
					}],
					buttons: [{
						text: ToloI18n.getMsg("ToloButtonPanelExt.winFiltroTemp.btnReset"),
						handler: function(b,e){
							var dtInizio = Ext.getCmp(this.getId() + 'dtInizio').setValue();
							var dtFine = Ext.getCmp(this.getId() + 'dtFine').setValue();
							this.fireEvent("onTemporalFilterApply", null, null);
						}, scope: this
					},{
						text: ToloI18n.getMsg("ToloButtonPanelExt.winFiltroTemp.btnApplica"),
						handler: function(b,e){
							var dtInizio = Ext.getCmp(this.getId() + 'dtInizio').getValue();
							var dtFine = Ext.getCmp(this.getId() + 'dtFine').getValue();
							this.fireEvent("onTemporalFilterApply", dtInizio, dtFine);
						}, scope: this
					},{
						text: ToloI18n.getMsg("ToloButtonPanelExt.winFiltroTemp.btnChiudi"),
						handler: function(){
							this.temporalFilterWindow.hide();
						}, scope: this
					}]
				})
			});

	},
	
	getLanguageIcon: function(lng){
		
		switch (lng){
			case 'it':
		  		return this.iconBasePath + 'Flags/ITA.png';
				break;
			case 'en':
				return this.iconBasePath + 'Flags/ENG.png';
				break;
		}
		
	},
	
	languageChange: function(lng){
		this.fireEvent('languageChange', lng);
	}, 
	
	checkFiller : function(item){
		// Non more filler are allowed
		 if(item == null)  return false;
		 
		 if ( 	(typeof item == 'string' && item == '->') || 
		 		(item.xtype && item.xtype == 'tbfill') ||
		 		(item.getXType && item.getXType() == 'tbfill')
		 	) 
		 {
		 	return true;
		 }
	},
		
	add : function(item){		
		 if(this.fillerAdded && this.checkFiller(item)) return;			 		 
		 this.callParent(arguments);
	},
	
	/**
	 * Method: addLeft
	 * Aggiunge l'item nell'ultima posizione del gruppo allineato a sinistra
	 * 
	 * Parameters:
	 * item - item da aggiungere alla toolar. 
	 */
	addLeft : function(item){
		if(this.checkFiller(item)) return;
		var fillerIndex = this.items.indexOf(this.filler);					
		this.insert(fillerIndex,item);
	},
		
	/**
	 * Method: addRight
	 * Aggiunge l'item nella prima posizione del gruppo allineato a destra
	 * 
	 * Parameters:
	 * item - item da aggiungere alla toolar. 
	 */
	addRight : function(item){			
		if(this.checkFiller(item)) return;
		var fillerIndex = this.items.indexOf(this.filler);					
		this.insert(fillerIndex+1,item);
	},
	
	/**
	 * Method: addFirst
	 * Aggiunge l'item in prima posizione
	 * 
	 * Parameters:
	 * item - item da aggiungere alla toolar. 
	 */
	addFirst : function(item){
		if(this.checkFiller(item)) return;
		this.insert(0,item);
	},
	
	/**
	 * Method: addLast
	 * Aggiunge l'item in ultima posizione
	 * 
	 * Parameters:
	 * item - item da aggiungere alla toolar. 
	 */
	addLast : function(item){
		this.add(item);
	},

	/**
	 * Method: encodeToggleGroup
	 * 
	 * Parameters:
	 * group - il gruppo da codificare. 
	 * 
	 * Returns:
	 * Il gruppo codificato.
	 */
	encodeToggleGroup: function(group) {
		return this.groupPrefix + group;
	},

	/**
	 * Method: decodeToggleGroup
	 * 
	 * Parameters:
	 * encodedGroup - il gruppo da decodificare.
	 * 
	 * Returns:
	 * Il gruppo codificato. 
	 */
	decodeToggleGroup: function(encodedGroup) {
		return encodedGroup.substr(this.groupPrefix.length);
	},		

	/**
	 * Method: addButton
	 * Add a single button. 
	 * 
	 * Parameters:
	 * btn - il pulsante da aggiungere.
	 * 
	 * Returns:
	 * Il componente aggiunto.
	 */
	addButton: function(btn) {
		//var cmp = Ext.ComponentMgr.create(btn, 'button');
		if (this.defaults && this.defaults.scale) Ext.applyIf(btn, {scale: this.defaults.scale} );
		var cmp = Ext.create('Ext.button.Button',btn);
		
		this.buttons.push(cmp);
		this.add(cmp);

		return cmp;
	},

	/**
	 * Method: addCombo
	 * 
	 * Parameters:
	 * btn - combo da aggiungere.
	 * 
	 * Returns:
	 * Il componente aggiunto.
	 */
	addCombo: function(cmb) {
		//var cmp = Ext.ComponentMgr.create(btn, 'button');
		//if (this.defaults && this.defaults.scale) Ext.applyIf(btn, {scale: this.defaults.scale} );		
		this.buttons.push(cmb);
		this.add(cmb);

		return cmb;
	},	
	
	/**
	 * Method: cmbSelectLayerHandler
	 * 
	 * Parameters:
	 * combo - la combo box.
	 * record - il record selezionato.
	 * index - l'indice del record.
	 * 
	 * Returns:
	 * {Boolean}
	 */
	cmbSelectLayerHandler: function (combo, record, index) {
		var eventName = 'onSelectLayer';
		this.fireEvent(eventName, record[0].data['codTPN']);
		return true
	},

	/**
	 * Method: btnToggleHandler
	 * 
	 * Parameters:
	 * button - il pulsante.
	 * state - lo stato del pulsante.
	 * 
	 * Returns:
	 * {Boolean}
	 */
	btnToggleHandler: function (button, state) {
		var retVal=true;
		if (button.handlerBaseName !=null) {
			var eventName = 'on' + button.handlerBaseName + ((state == true) ? 'PressFn' : 'ReleaseFn');
			
			if(state && button.becomeDefault){
				for (var i=0; i<this.buttons.length; i++) {
					if (this.buttons[i].toggleGroup==button.toggleGroup) {
						this.buttons[i].groupDefault = false;
					}
				}
				button.groupDefault = true;
			}
			
			this.fireEvent(eventName, button);			

			/*
			// Necessario per fare in modo che annullaselezioni non rimanga premuto, pur essendo parte di un gruppo di toggle 
			if (button.opCode ==  TolomeoExt.ToloAPIOpCodes.btnAnnullaSelezioni)  {
					this.pressDefault(this.decodeToggleGroup(button.toggleGroup));
					state=false;
					retVal=false;
			}
			 */
		}
		return retVal;
	},

	/**
	 * Method: btnClickHandler
	 * 
	 * Parameters:
	 * button - il pulsante.
	 * e - l'evento.
	 * 
	 * Returns:
	 * {Boolean}
	 */
	btnClickHandler: function (button, e) {
		if (button.handlerBaseName !=null) {
			var eventName = 'on' + button.handlerBaseName + 'PressFn';
			this.fireEvent(eventName, button);
		}

		// Necessario per premere bottone default quando premuto annulla selezioni 
		if (button.opCode ==  TolomeoExt.ToloAPIOpCodes.btnAnnullaSelezioni)  {
			this.pressDefault(this.decodeToggleGroup(button.toggleGroup));
		}

		// Necessario per premere bottone default quando premuto annulla selezioni 
		if (button.opCode ==  TolomeoExt.ToloAPIOpCodes.btnTemporalFilter)  {
			this.temporalFilterWindow.show();
		}
		
		return true;
	},

	/**
	 * Method: btnMeasureMng
	 * 
	 * Parameters:
	 * button - il pulsante.
	 * state - l'evento.
	 */
	btnMeasureMng: function(button, state) {

		var itm = null;

		// Determina quale voce di menù è selezionata
		for (var i= 0; i<button.menu.items.items.length; i++) {
			if (button.menu.items.items[i].checked) itm=button.menu.items.items[i]; 
		}

		if (itm!=null) {
			var eventName = 'onMeasure' + ((state == true) ? 'Activate' : 'Deactivate');
			this.fireEvent(eventName, itm.measureType);
		}

		// tolto perchè va in conflitto con altre funzionalità
		//if (!state) this.pressDefault(this.decodeToggleGroup(button.toggleGroup));

	},

	/**
	 * Method: btnMeasureItemMng
	 * 
	 * Parameters:
	 * button - il pulsante.
	 * checked - indica se il pulsante è premuto o meno.
	 */
	btnMeasureItemMng: function(button, checked) {

		if (checked) {
			switch (button.measureType) {
			case 0:
				this.btnMeasure.setIcon(this.iconBasePath + 'misurapoligono.gif');
				break;
			case 1:
				this.btnMeasure.setIcon(this.iconBasePath + 'misuracerchio.gif');
				break;
			case 2:
				this.btnMeasure.setIcon(this.iconBasePath + 'misuralinea.gif');
				break;
			}	
		}

		if ((checked) && (this.btnMeasure.pressed)) {	
			var eventName = 'onMeasureTypeChange';
			this.fireEvent(eventName, button.measureType);
		}

		if (checked) this.btnMeasure.toggle(true);

	},
	
	
	btnNewToggleHandler: function(button, state) {
		this.btnToggleHandler(button,state);
		if (!state) this.pressDefault(this.decodeToggleGroup(button.toggleGroup));
	},
	
	/**
	 * Method: btnNewItemMng
	 * 
	 * Parameters:
	 * button - il pulsante.
	 * checked - indica se il pulsante è premuto o meno.
	 */
	btnNewItemMng: function(button, checked) {

		if (checked) {											
			if(this.btnNew.pressed) {
				/*
				var eventName = 'onNewTypeChange';
				this.fireEvent(eventName, button);				
				this.btnNew.toggle();
				this.pressDefault(this.decodeToggleGroup(button.toggleGroup));
				*/
				this.fireEvent('onNuovoReleaseFn', this.btnNew);
				this.fireEvent('onNuovoPressFn', button);
				
			}
			this.btnNew.setIcon(button.icon);							
			this.btnNew.newType = button.newType;				
			//this.btnNew.toggle(true);
		}
	},

	/**
	 * Method: pressDefault
	 * 
	 * Parameters:
	 * group - il gruppo.
	 */
	pressDefault: function(group) {
		for (var i=0; i<this.buttons.length; i++) {
			if ((this.buttons[i].toggleGroup) && (this.buttons[i].toggleGroup==this.encodeToggleGroup(group)) && (this.buttons[i].groupDefault) && (this.buttons[i].groupDefault==true) ) {
				this.buttons[i].toggle(true);
			}
		}

		// bottoni.press(bottoni.getDefaultName(group));
		//alert("PressDefault del gruppo "+ group);
	},

	/**
	 * Method: operationEnable
	 * 
	 * Parameters:
	 * opCode - codice operazione.
	 * enabled - indica se l'operazione è abilitata.
	 */
	operationEnable: function(opCode, enabled) {
		var thisPanel = this;
		this.items.each(
				function (item, index, length) {
					if (item.opCode == opCode){
						(thisPanel.paramsJS.layOut.nascondiBottoniInattivi) ? item.setVisible(enabled) : item.setDisabled(!enabled);
						if(opCode == TolomeoExt.ToloAPIOpCodes.btnSnap){							
							if(!enabled && item.pressed){
								item.toggle();
							} else if (enabled && item.pressed){
								item.toggle();
								item.toggle();
							}
						}
					}
				}	
		);
	},

	/**
	 * Method: bindToAPI
	 * 
	 * Parameters:
	 * api - API.
	 */
	bindToAPI: function(api) {
		this.api=api;
		// Eventi API ai quali viene registrato buttonsPanel
		api.on('onOperationEnable', function (opCode) {this.operationEnable(opCode, true);}, this );
		api.on('onOperationDisable', function (opCode) {this.operationEnable(opCode, false);}, this );
		api.on('onOperationPressDefault', function (group) {this.pressDefault(group);}, this );
		api.on('selectedObjectsRemoved', 
			function (removedGeoms,geoms) {
				var geom = geoms.geometries?geoms.geometries[0]:geoms;
				if (this.withLayerList && this.cmbLayerSel.getValue() != geom.codTPN && this.paramsJS.isSelectable(geom.codTPN)){					
					this.cmbLayerSel.setValue(geom.codTPN);
					//this.fireEvent('onSelectLayer', geom.codTPN);
				}
			}, 
			this );
		api.on('onObjectSelect', function(geoms){
			var geom = geoms.geometries?geoms.geometries[0]:geoms;
			var codTpn = geom.codTPN;
			if (this.withLayerList && this.cmbLayerSel.getValue() != codTpn){					
				this.cmbLayerSel.setValue(codTpn);
			}
		},this);
		
		if (this.withLayerList) api.setCurrentSelectLayer(this.cmbLayerSel.getValue());
		
		if (this.withNavHistory) {
			this.api.on('previousNavigationStateAvailable',		function(){Ext.getCmp(this.getId() + 'HistoryPrevBtn').setDisabled(false)}, this);
			this.api.on('previousNavigationStateNotAvailable',	function(){Ext.getCmp(this.getId() + 'HistoryPrevBtn').setDisabled(true)}, this);
			this.api.on('nextNavigationStateAvailable',			function(){Ext.getCmp(this.getId() + 'HistoryNextBtn').setDisabled(false)}, this);
			this.api.on('nextNavigationStateNotAvailable',		function(){Ext.getCmp(this.getId() + 'HistoryNextBtn').setDisabled(true)}, this);	
		}
		
	},

	//TODO è anche in API, riunificare in quelche modo
	/**
	 * Method: autoIdentifyLayersPresent
	 * 
	 * Returns:
	 * {Boolean}
	 */
	autoIdentifyLayersPresent: function (){

		for(var index=0; index<this.paramsJS.azioniEventi.eventiLayerList.length; index++) {
			var paramJSLayer = this.paramsJS.azioniEventi.eventiLayerList[index];
			if (paramJSLayer.autoIdentifyAllowed==true)  {
				return true;
			}
		}
		return false;
	}, 
	
	/**
	 * Imposta un stato o cambia lo stato di un bottone identificato tramite il suo opCode
	 * 
	 * @param opCode: codice del bottone (vedi toloAPIOpCodes.js)
	 * @param state: lo stato da impostare (opzionale). Se	non impostato o null cambia lo stato corrente
	 * @param supress: stoppa il fire degli eventi innescati dal cambio di stato
	 */
	buttonToggle: function(opCode, state, supress) {
		
		for (var i=0; i<this.buttons.length; i++) {
			if (this.buttons[i].opCode==opCode) {
				this.buttons[i].toggle(state, supress);
			}
		}
		
	},
	
	a: function(data) {
	//	this.cmbLayerSel.lastQuery=null;
		if (this.cmbLayerSel) {
			this.cmbLayerSel.getStore().loadData(data, false);
			this.cmbLayerSel.getStore().filterBy(this.withSearchLayerFilter);
		}
		
	},
	
	/**
	 * Enable/Disable the button having that specific id 
	 * 
	 * @param id: id of the button
	 * @param on: boolean. True to enable button, false to disable
	 */
	enableButton : function(id,on){
		var comp = Ext.getCmp(id);
		if(comp) comp.setDisabled(!on);
	},
			
	/**
	 * Enable(Show)/Disable(Hide) buttons relate to toc 
	 * 
	 * @param tocExist: flag true/false 
	 * @param on: boolean. True to enable button, false to disable
	 */
	switchTocRelatedButtons : function(tocExist,on){
		this.enableButton(this.getId() + 'permalinkBtn',on);
		var comp = Ext.getCmp(this.getId() + 'toolsMenu');
		if(comp && tocExist){
			//var comp = Ext.getCmp(this.getId() + 'toolsMenu');
			if(comp) comp.setVisible(on);			
			this.enableButton(this.getId() + 'exportQgisBtn',on);
		}
	}
		
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITA' o
 IDONEITA' PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.define('TolomeoExt.ToloInsFromLayerPanel', {

	extend: 'Ext.FormPanel',
	
	/**
	 * @param jsGeometryList {JSGeometryArray}
	 */
	jsGeometryList: null,
	
	initComponent: function(){
		
		this.addEvents("geompartitemmouseenter");
		this.addEvents("geompartitemmouseleave");
		this.addEvents("exitOK");
		this.addEvents("exitCancel");
		
		thisFormPanel = this;
	    
		this.layout = { type: 'vbox', align: 'stretch'};
	    this.minButtonWidth = 50;
	    
		//this.layout = 'vbox';
	
		var objRadioItems = [];
		for (var i=0; i<this.jsGeometryList.size(); i++) {
			var o = this.jsGeometryList.getByIndex(i);
			objRadioItems.push(Ext.create('Ext.form.field.Checkbox',{boxLabel: o.description, name: 'jsGeomToInsert', inputValue: o.toString(), checked: (i==0)}));
		}
		
		var objRadioGroup = {
            xtype: 'radiogroup',
            //fieldLabel: 'Auto Layout',
            //cls: 'x-check-group-alt',
            
            items: objRadioItems
        }
		
		var objRadioFieldset = {	
            xtype: 'fieldset',
            
            title: ToloI18n.getMsg("ToloInsFromLayerPanel.objRadioFieldset.title"),
            layout: 'anchor',
            /*defaults: {
                anchor: '100%',
                hideEmptyLabel: false
            },*/
            items: [objRadioGroup]
		};
		
		// Cerco le parti del primo oggetto
		var o1 = this.jsGeometryList.getByIndex(0);
		var o1Parts = o1.getParts();
		//var partsCheckItems = [];
		var storeData = [];
		
		for (var i=0; i<o1Parts.size(); i++){
			var p = o1Parts.getByIndex(i);
			var nomeParte = ToloI18n.getMsg("ToloInsFromLayerPanel.objRadioFieldset.title", {NUMPARTE: i});
			storeData.push([true, nomeParte, p]);
		}
		
		
		var store = Ext.create('Ext.data.ArrayStore', {
		    // store configs
		    //storeId: 'myStore',
		    // reader configs
			autoSync: true,
		    fields: [
		       'active',
		       'description',
		       'val'
		    ],
		    data: storeData
		});
		
		
    	var listView = Ext.create('Ext.grid.Panel',{
    		store: store,
    		flex: 1,
    		//autoWidth: true,
    		//emptyText: 'Descrizione non recuperata',
    		viewConfig: {
    			//firstCls: null,
    			trackOver: true
    		},
    		
    		//reserveScrollOffset: true,
    		//multiSelect: false,
    		listeners: {
    			'itemmouseenter': { fn: this.itemmouseenter, scope: this},
    			'itemmouseleave': { fn: this.itemmouseleave, scope: this}//,
    			//'itemclick':      { fn: this.onQuerySingleResultByIndex, scope: this}
    		},
    		columns: [
    		          { xtype : 'checkcolumn',
    			//header: 'active',
    			width: 30,
    			//flex: 1,
    			dataIndex: 'active'
    		},{
    			header: ToloI18n.getMsg("ToloInsFromLayerPanel.listaParti.header.descrizione"),
    			//width: 1,
    			flex: 1,
    			dataIndex: 'description'
    		}]
    	});
		/*
		this.items= [ objRadioFieldset , 
		              listView,{
	        xtype: 'hiddenfield',
	        name: 'geoms'
	     
	    }];*/
		this.items= [objRadioFieldset, listView];
		
		this.buttons= [{
			text: ToloI18n.getMsg("ToloInsFromLayerPanel.btnNessuno.text"),
            flex: 1,
            handler: function(){
            	for (var i=0; i<store.getCount(); i++) {
        			var r = store.getAt(i);
        			r.set('active',false);
        		}
            }
        },{
        	text: ToloI18n.getMsg("ToloInsFromLayerPanel.btnTutti.text"),
            flex: 1,
            handler: function(){
            	for (var i=0; i<store.getCount(); i++) {
        			var r = store.getAt(i);
        			r.set('active',true);
        		}

            }
        },{
        	text: ToloI18n.getMsg("ToloInsFromLayerPanel.btnOk.text"),
            flex: 1,
            handler: function(){
               if(thisFormPanel.getForm().isValid()){
            	   var bAll = true;
            	   var g = new JSGeometryArray();
            	   for (var i=0; i<store.getCount();i++){
            		   r=store.getAt(i);
            		   if (r.get("active")){
            			   g.add(r.get("val"));
            		   } else {
            			   bAll = false;   
            		   }
            	   }
            	   /*
            	   if (g.size()>0) {
            		   thisFormPanel.getForm().setValues({geoms: g.toString()});
            	   }
            	   */
            	   thisFormPanel.fireEvent("exitOk", o1, g, bAll);
            	   /*
                    Ext.Msg.alert('Submitted Values', 'The following will be sent to the server: <br />'+
                    		thisFormPanel.getForm().getValues(true).replace(/&/g,', '));*/
                }
            }
        },{
            text: ToloI18n.getMsg("ToloInsFromLayerPanel.btnAnnulla.text"),
            flex: 1,
            handler: function(){
            	thisFormPanel.fireEvent("exitCancel");
            }
        }];
		
		this.callParent();
		//this.doLayout();
		
	},
	
	itemmouseenter: function(grid, record, item, index, e, eOpts) {
		this.fireEvent("geompartitemmouseenter", record);
	},
	
	itemmouseleave: function(grid, record, item, index, e, eOpts) {
		this.fireEvent("geompartitemmouseleave", record);
	}

});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITA' o
 IDONEITA' PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.define('TolomeoExt.ToloSelectGeoms', {

	extend: 'Ext.FormPanel',
	
	/**
	 * @param jsGeometryList {JSGeometryArray}
	 */
	jsGeometryList: null,
	
	initComponent: function(){
		
		this.addEvents("geomItemClick");
		this.addEvents("selectedGeomsChange");
		this.addEvents("selectAllPressed");
		this.addEvents("selectNonePressed");
		this.addEvents("mostraPressed");
		this.addEvents("exitOK");
		this.addEvents("exitCancel");
		
		var thisFormPanel = this;
	    
		this.layout = { type: 'vbox', align: 'stretch'};
	    this.minButtonWidth = 50;
	    
		//this.layout = 'vbox';
		
		var storeData = [];
		for (var i=0; i<this.jsGeometryList.size(); i++) {
			var o = this.jsGeometryList.getByIndex(i);
			storeData.push([true, i, o]);
			//objRadioItems.push(Ext.create('Ext.form.field.Checkbox',{boxLabel: o.description, name: 'jsGeomToInsert', inputValue: o.toString(), checked: (i==0)}));
		}
		
		this.store = Ext.create('Ext.data.ArrayStore', {
		    // store configs
		    //storeId: 'myStore',
		    // reader configs
			autoSync: true,
		    fields: [
		       'active',
		       'description',
		       'val'
		    ],
		    data: storeData
		});
		
		
    	var listView = Ext.create('Ext.grid.Panel',{
    		store: this.store,
    		flex: 1,
    		//autoWidth: true,
    		//emptyText: 'Descrizione non recuperata',
    		viewConfig: {
    			//firstCls: null,
    			trackOver: true
    		},
    		
    		//reserveScrollOffset: true,
    		//multiSelect: false,
    		listeners: {
    			'itemclick': { fn: this.itemclick, scope: this}
    		},
    		columns: [
    		          { xtype : 'checkcolumn',
    			//header: 'active',
    			width: 30,
    			//flex: 1,
    			dataIndex: 'active',
    			listeners: { 
    				'checkChange': { fn: this._selectedGeomsChange, scope: this}
    			}
    		},{
    			header: ToloI18n.getMsg("ToloSelectGeoms.header"),
    			//width: 1,
    			flex: 1,
    			dataIndex: 'description'
    		}]
    	});
		/*
		this.items= [ objRadioFieldset , 
		              listView,{
	        xtype: 'hiddenfield',
	        name: 'geoms'
	     
	    }];*/
		this.items= [listView];
		
		this.buttons= [{
            text: ToloI18n.getMsg("ToloSelectGeoms.btnNessuno"),
            flex: 1,
            handler: function(){
            	for (var i=0; i<thisFormPanel.store.getCount(); i++) {
        			var r = thisFormPanel.store.getAt(i);
        			r.set('active',false);
        		}
            	thisFormPanel._validaForm();
            	thisFormPanel.fireEvent("selectNonePressed");
            	thisFormPanel.fireEvent('selectedGeomsChange', thisFormPanel.getSelectedGeometryArray());
            }
        },{
            text: ToloI18n.getMsg("ToloSelectGeoms.btnTutti"),
            flex: 1,
            handler: function(){
            	for (var i=0; i<thisFormPanel.store.getCount(); i++) {
        			var r = thisFormPanel.store.getAt(i);
        			r.set('active',true);
        		}
            	thisFormPanel._validaForm();
            	thisFormPanel.fireEvent("selectAllPressed");
            	thisFormPanel.fireEvent('selectedGeomsChange', thisFormPanel.getSelectedGeometryArray());
            }
        },{
            text: ToloI18n.getMsg("ToloSelectGeoms.btnMostra"),
            flex: 1,
            handler: function(){
            	thisFormPanel.fireEvent("mostraPressed");

            }
        },{
            text: ToloI18n.getMsg("ToloSelectGeoms.btnOK"),
            flex: 1,
            id: this.id + 'idOkButton',
            handler: function(){
               if(thisFormPanel.getForm().isValid()){
            	   var g = thisFormPanel.getSelectedGeometryArray();
            	   /*var g = new JSGeometryArray();
            	   for (var i=0; i<thisFormPanel.store.getCount();i++){
            		   r=thisFormPanel.store.getAt(i);
            		   if (r.get("active")){
            			   g.add(r.get("val"));
            		   }
            	   }*/
            	   thisFormPanel.fireEvent("exitOk", g);
                }
            }
        },{
            text: ToloI18n.getMsg("ToloSelectGeoms.btnAnnulla"),
            flex: 1,
            handler: function(){
            	thisFormPanel.fireEvent("exitCancel");
            }
        }];
		
		this.callParent();
		
	},
	
	getSelectedGeometryArray: function(){
		var g = new JSGeometryArray();
 	   	for (var i=0; i<this.store.getCount();i++){
 		   r=this.store.getAt(i);
 		   if (r.get("active")){
 			   g.add(r.get("val"));
 		   }
 	   	}
 	   	return g;
		
	},
	
	itemclick: function(grid, record, item, index, e, eOpts) {
		this.fireEvent("geomItemClick", record.get("val"));
	},
	
	_validaForm: function(){
		var okBtn = Ext.getCmp(this.id + 'idOkButton');
		var g = this.getSelectedGeometryArray();
		
		if (g.size()==0) {
			okBtn.setDisabled(true);
		} else {
			okBtn.setDisabled(false);
		}
	},
	
	_selectedGeomsChange: function(rowIndex, checked, eOpts){
		this._validaForm();
		this.fireEvent('selectedGeomsChange', this.getSelectedGeometryArray());
	}
	

});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * TolomeoExt.lazyLoad
 *
 * @author Nieri Federico
 *******************************************************************
 * Class TolomeoExt.lazyLoad
 * Load javascript files onDemand
 **/
TolomeoExt.lazyLoad = function () {

    var debug = false;
    var containingScriptNames = ['build/toloExt-all.js','build/toloExt-all-debug.js','build/toloExt-all-noext.js','build/toloExt-all-noext-debug.js'];
    var thisScriptName = 'toloLazyLoad.js';
    
    var objects = {
 //       gmap: {
 //           loaded: false,
 //           checkLoad: 'GMap2', /*Variable that must exists to confirm load*/           
 //           url: 'http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAZtXebGuEUyPUsb16TunzchQH1vzzQPdXCsLMkqVnPRtWvfSdoRToJrguncXU9Z0FgvbgReXeej9BDQ&sensor=false&async=2'
 //       },        
        proj4js: {
            loaded: false,
            checkLoad: 'Proj4js',
            relativeToThisScript : true,
            url: '../ext/proj4js/proj4js-compressed.js'
        }, 
		swfobject: {
            loaded: false,
            checkLoad: 'swfobject',
            relativeToThisScript : true,
            url: '../ext/swfobject/swfobject.js'
        },
        mootools12corecompressed: {
            loaded: false,
            checkLoad: 'MooTools',
            relativeToThisScript : true,
            url: '../ext/mootools/mootools-1.2-core-compressed.js'
        },
        mootools12morecompressed: {
            loaded: false,
            checkLoad: 'Drag',
            relativeToThisScript : true,
            url: '../ext/mootools/mootools-1.2-more-compressed.js'
        },
        iipmooviewer11compressed: {
            loaded: false,
            checkLoad: 'IIP',
            relativeToThisScript : true,
            url: '../ext/iipmooviewer/iipmooviewer-1.1.js'
        },
        mootoolscore145: {
            loaded: false,
            checkLoad: 'MooTools',
            relativeToThisScript : true,
            url: '../ext/mootools/mootools-core-1.4.5-full-nocompat-yc.js'
        },
        mootoolsmore1401: {
            loaded: false,
            checkLoad: 'Drag',
            relativeToThisScript : true,
            url: '../ext/mootools/mootools-more-1.4.0.1-compressed.js'
        },
        iipmooviewer20: {
            loaded: false,
            checkLoad: 'IIPMooViewer',
            relativeToThisScript : true,
            url: '../ext/iipmooviewer-2.0/javascript/iipmooviewer-2.0-compressed.js'
            //url: '../ext/iipmooviewer-2.0/src/iipmooviewer-2.0.js'
        },
        /*
        i18nPropertyReader: {
            loaded: false,
            checkLoad: 'Ext.i18n.PropertyReader',
            relativeToThisScript : true,
            url: '../ext/resourceBundle/PropertyReader.js'
        },
        i18nBundle: {
            loaded: false,
            checkLoad: 'Ext.i18n.Bundle',
            relativeToThisScript : true,
            url: '../ext/resourceBundle/Bundle.js'
        },*/
        
        i18nPropertyReader: {
            loaded: false,
            checkLoad: 'Ext.i18n.PropertyReader',
            relativeToThisScript : true,
            url: '../ext/i18n/reader/Property.js'
        },
        i18nJsonReader: {
            loaded: false,
            checkLoad: 'Ext.i18n.reader.Json',
            relativeToThisScript : true,
            url: '../ext/i18n/reader/Json.js'
        },
        i18nBundle: {
            loaded: false,
            checkLoad: 'Ext.i18n.Bundle',
            relativeToThisScript : true,
            url: '../ext/i18n/Bundle.js'
        },
        cswExplorer: {
            loaded: false,
            checkLoad: 'CSWPanel',
            relativeToThisScript : true,
            url: 'build/cswExplorer.js'
        },
        cesium: {
            loaded: false,
            checkLoad: 'Cesium',
            relativeToThisScript : true,
            url: '../ext/cesium/Build/Cesium/Cesium.js'
        }
    }
    
    return {
    	getScriptLocation: function () {    
    		if(TolomeoExt.lazyLoad.libPath) return TolomeoExt.lazyLoad.libPath;
    		
	        var scripts = document.getElementsByTagName('script');
	        for (var i = 0; i < scripts.length; i++) {
	            var src = scripts[i].getAttribute('src');
	            if (src) {
	            	//Elimina eventuale querystring
		            var p = src.lastIndexOf("?");
		            if (p!=-1) {
		            	src=src.substring(0,p);
		            }
	                var index = src.lastIndexOf(thisScriptName);
	                var scriptNameLen = thisScriptName.length;	                
	                // is it found, at the end of the URL?
	                if ((index > -1) && (index + scriptNameLen == src.length)) {
	                	TolomeoExt.lazyLoad.libPath = src.slice(0, -scriptNameLen);
	                    return TolomeoExt.lazyLoad.libPath;
	                }	            	
	            }
	        }
	        for (var i = 0; i < scripts.length; i++) {
	            var src = scripts[i].getAttribute('src');
	            if (src) {
	            	//Elimina eventuale querystring
		            var p = src.lastIndexOf("?");
		            if (p!=-1) {
		            	src=src.substring(0,p);
		            }
		            
	            	for(var s = 0; s < containingScriptNames.length; s++){
	            		var scriptName  = containingScriptNames[s];
		                var index = src.lastIndexOf(scriptName);
		                var scriptNameLen = scriptName.length;	                
		                // is it found, at the end of the URL?
		                if ((index > -1) && (index + scriptNameLen == src.length)) {
		                	TolomeoExt.lazyLoad.libPath = src.slice(0, -scriptNameLen);
		                    return TolomeoExt.lazyLoad.libPath;
		                }
	            	}
	            }
	        }
	        return "";
	    },
	    
        /*
         * @name Ext.ux.lazyLoad.get
         * Retrieve js files on demand if not loaded
         * @params
         *  -jsKey {String}: Js File name to load
         *  -callback {function}: function to be executed after
         *  -scope {Object}: Object scope to run the callback function
         **/
        get: function (jsKey, onLoad, onFail, scope) {
            /*Return if is not a valid object*/
            if (!objects[jsKey]) return false;

            /*Run thread*/
            var waitCounter = 0;
            this.thread(jsKey, onLoad, onFail, scope, waitCounter, 'loadScript' + Ext.id());
            return true;
        }
        /*
         *@name Ext.ux.lazyLoad.thread
         *Reusable thread to check if js file has been loaded
         *@params
         *  -jsKey{String}: js key from the objects array
         *  -callback{Function}: function to execute when file is loaded
         *  -scope {Object}: Object scope to run the callback function
         *  -waitCointer{Integer}: Current cycle number
         *  -id{String}: Id used to identify the script tag
         **/
        ,
        thread: function (jsKey, onLoad, onFail, scope, waitCounter, id) {

            /*If its loaded*/
            if (this.isLoaded(jsKey)) {
                onLoad.call(scope);
            } else {
                /*If script object hasnt been included, do it*/
                if (!Ext.get(id)) {
                    /*If hasnt been loaded*/
                    /*Prepare url*/
                    var url = objects[jsKey].url;
                    if(objects[jsKey].relativeToThisScript){
                    	url = this.getScriptLocation()+ url;
                    }

                    this.head = document.getElementsByTagName('head').item(0);
                    script = document.createElement('script');
                    script.defer = false;
                    script.src = url;
                    script.type = 'text/javascript';
                    script.id = id;
                    script.idDefer = null;
                    var me = this;
                    script.onload = function(){me.endLoading(true,onLoad,scope,id,jsKey);};
      				script.onerror = function(){me.endLoading(false,onFail,scope,id,jsKey);};
      				
      				if (Ext.isIE) {
				        script.onreadystatechange = function(){me.checkReadyState(this.readyState,onLoad,onFail,scope,id,jsKey);};
				    }
				    
                    this.head.appendChild(script);
                }
                //if (debug) Ext.get('testdiv').insertHtml('beforeEnd', jsKey + ' wait counter:' + waitCounter + '<br>');
                //console.debug(jsKey + ' wait counter:' + waitCounter);
                if(this.checkLoad(jsKey)){
                    this.endLoading(true,onLoad,scope,id,jsKey);
                    return;
                   
                } else {
                    if (waitCounter++<10) {
                        /*Will check 10 times every 2 seconds if the js has been loaded*/
                    	var scriptTag = document.getElementById(id);
                        scriptTag.idDefer = Ext.defer(this.thread,2000, this, [jsKey, onLoad, onFail, scope, waitCounter, id]);
                    } else {
                    	this.endLoading(false,onFail,scope,id,jsKey);
                    }
                }

            }
        },
        
        checkLoad : function(jsKey){        
        	try {
                return eval(objects[jsKey].checkLoad);                
            } catch(e) {
            	return false;
          	}
        },
        
        endLoading : function(ok,callMe,scope,id,jsKey){
        	this.clear(id);
        	if(ok){        		
        		objects[jsKey].loaded = true;
        	}else{
        		this.clean(id);
        	}
        	if(callMe){
        		callMe.call(scope);
        	}else if(!ok){
        		alert(ToloI18n.getMsg("lazyLoad.ErroreCaricamento"));
        	}
        	
        },
        
        checkReadyState: function(readyState,onLoad,onFail,scope,id,jsKey) {
	      if (readyState == 'loaded') {
	        if(this.checkLoad(jsKey)){                
                this.endLoading(true,onLoad,scope,id,jsKey);                
            } else {
            	this.endLoading(false,onFail,scope,id,jsKey);
          	}
	      }
	    },
	    
        clear: function (id) {
            var scriptTag = document.getElementById(id);
            if (scriptTag && scriptTag.idDefer) clearTimeout(scriptTag.idDefer);
        }
        /*
         * @name Ext.ux.lazyLoad.clean
         * Removes recently used script tag from dom
         **/
        ,
        clean: function (id) {
            var scriptTag = document.getElementById(id);
            if (scriptTag) this.head.removeChild(scriptTag);
        }
        /*
         * @name Ext.ux.lazyLoad.isLoaded
         * Getter function to retrieve status
         **/
        ,
        isLoaded: function (jsKey) {
            return objects[jsKey].loaded;
        }
    }
}();/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.Projection
 * 
 * 
 */
Ext.define('TolomeoExt.Projection', {

	extend: 'Object',

	statics: {
	
		/**
		 * @property {Object} [transforms={}]
		 * Transforms is an object, with from properties, each of which may
		 * have a to property. This allows you to define projections without 
		 * requiring support for proj4js to be included.
		 *
		 * This object has keys which correspond to a 'source' projection object.  The
		 * keys should be strings, corresponding to the projection.getCode() value.
		 * Each source projection object should have a set of destination projection
		 * keys included in the object. 
		 * 
		 * Each value in the destination object should be a transformation function,
		 * where the function is expected to be passed an object with a .x and a .y
		 * property.  The function should return the object, with the .x and .y
		 * transformed according to the transformation function.
		 *
		 * Note - Properties on this object should not be set directly.  To add a
		 *     transform method to this object, use the "addTransform" method.  For an
		 *     example of usage, see the OpenLayers.Layer.SphericalMercator file.
		 */
		transforms: {},

		/**
		 * @method addTransform
		 * Set a custom transform method between two projections.  Use this method in
		 * cases where the proj4js lib is not available or where custom projections
		 * need to be handled.
		 * 
		 * @param {String} from
		 * The code for the source projection
		 * 
		 * @param {String} to
		 * the code for the destination projection
		 * 
		 * @param {Function} method
		 * A function that takes a point as an argument and
		 * transforms that point from the source to the destination projection
		 * in place.  The original point should be modified.
		 * 
		 */
		addTransform: function(from, to, method) {
		    if(!TolomeoExt.Projection.transforms[from]) {
		        TolomeoExt.Projection.transforms[from] = {};
		    }
		    TolomeoExt.Projection.transforms[from][to] = method;
		},

		/**
		 * @method transform
		 * Transform a point coordinate from one projection to another.  Note that
		 * the input point is transformed in place.
		 * 
		 * @param {TolomeoExt.Point/Object} point
		 * An object with x and y
		 * properties representing coordinates in those dimensions.
		 *
		 * @param {TolomeoExt.Projection/String} source
		 * Source map coordinate system
		 * 
		 * @param {TolomeoExt.Projection/String} dest
		 * Destination map coordinate system
		 *
		 * @return {TolomeoExt.Point/Object}
		 * A transformed coordinate.  The original point is modified.
		 * 
		 */
		transform: function(point, source, dest) {
			if(Ext.isString(source)){
				source = new TolomeoExt.Projection(source);
			}
			if(Ext.isString(dest)){
				dest = new TolomeoExt.Projection(dest);
			}
		    if (source.proj && dest.proj) {
		        var proj4Point = Proj4js.transform(source.proj, dest.proj, point);
		    } else if (source && dest && 
		        TolomeoExt.Projection.transforms[source.getCode()] && 
		        TolomeoExt.Projection.transforms[source.getCode()][dest.getCode()]) {
		        TolomeoExt.Projection.transforms[source.getCode()][dest.getCode()](point); 
		    }
		    return new Point(proj4Point.x,proj4Point.y);
		},

		/**
		 * @method addDefinition
		 * Add at runtime a custom definition of a source projection
		 * 
		 * @param {String} projCode
		 * The code for the source projection
		 * 
		 * @param {String} def
		 * source projection definition
		 * 
		 */
		addDefinition: function(projCode,def){
			TolomeoExt.Projection.defs[projCode] = def;
		},


		/**
		 * @method loadDefinition
		 * Load the definition of a source projection if it doesn't already exist
		 * 
		 * @param {String} projCode
		 * The code for the source projection
		 * 
		 */
		loadDefinition: function(projCode){
			if (window.Proj4js) {
				if(!window.Proj4js.defs[projCode] && TolomeoExt.Projection.defs[projCode]){
					window.Proj4js.defs[projCode] = TolomeoExt.Projection.defs[projCode];
				} else {
					new Proj4js.Proj(projCode);
				}
		    }
		},
		
    /**
     * @property {Object} defs
     * 
     */
		defs: { "EPSG:3003": "+proj=tmerc +lat_0=0 +lon_0=9 +k=0.9996 +x_0=1500000 +y_0=0 +ellps=intl +towgs84=-104.1,-49.1,-9.9,0.971,-2.917,0.714,-11.68 +units=m +no_defs",
				"EPSG:25832": "+proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs"}
	},

	
    /**
     * @property {Object} proj
     * Proj4js.Proj instance.
     * 
     */
    proj: null,
    
    /**
     * @property {String} projCode
     * 
     */
    projCode: null,
	
	/**
	 * @constructor
	 * 
	 * 
	 * @param {Object} config
	 * 
	 * 
	 */
	constructor : function(config){
		if(Ext.isString(config)){            
			config = {projCode: config};
		}        
		Ext.apply(this, config);  
		if (window.Proj4js) {
			if(!window.Proj4js.defs[this.projCode] && TolomeoExt.Projection.defs[this.projCode]){
				window.Proj4js.defs[this.projCode] = TolomeoExt.Projection.defs[this.projCode];
			}
	        this.proj = new Proj4js.Proj(this.projCode);                        
	    }
	},
	 
	
    /**
     * @method getCode
     * Get the string SRS code.
     *
     * @return {String}
     * The SRS code.
     */
    getCode: function() {
        return this.proj ? this.proj.srsCode : this.projCode;
    },
   
    /**
     * @method getUnits
     * Get the units string for the projection -- returns null if 
     * proj4js is not available.
     *
     * @return {String}
     * The units abbreviation.
     * 
     */
    getUnits: function() {
        return this.proj ? this.proj.units : null;
    },
    
    /**
     * @method getTitle
     * 
     *
     * @return {String}
     * 
     * 
     */
    getTitle: function() {
        return this.proj ? (this.proj.title ? this.proj.title : this.proj.srsCode) : null;
    },

    /**
     * @method toString
     * Convert projection to string (getCode wrapper).
     * 
     * @return {String}
     * The projection code.
     * 
     */
    toString: function() {
        return this.getCode();
    },

    /**
     * @method equals
     * Test equality of two projection instances.  Determines equality based
     * soley on the projection code.
     *
		 * @param {TolomeoExt.Projection} projection
		 * 
		 * 
		 * @return {Boolean}
     * The two projections are equivalent.
     * 
     */
    equals: function(projection) {
        if (projection && projection.getCode) {
            return this.getCode() == projection.getCode();
        } else {
            return false;
        }    
    },
		
		/**
     * @method destroy
     * Destroy projection object.
     * 
     */
    destroy: function() {
        delete this.proj;
        delete this.projCode;
    }
});     

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.ToloMapAPIExt
 * Funzioni pubbliche di controllo della mappa (posizione, zoom, evidenziazioni, etc.). 
 *
 * Inherits from:
 *  - <Ext.util.Observable>
 *
 */

Ext.define('TolomeoExt.ToloMapAPIExt', {
	
	 //mixins: {
     //   observable: 'Ext.util.Observable'
    //},


	extend: 'Ext.util.Observable',
	
//TolomeoExt.ToloMapAPIExt = Ext.extend(Ext.util.Observable,{
		
	// Variabili e costanti

	
	/*
	 * 
	 * fonte: http://wiki.openstreetmap.org/wiki/Zoom_levels
	 * The 'degree' column gives the map width in degrees, for map at that zoom level which is 256 pixels wide. 
	 * Values listed in the column "m / pixels" gives the number of meters per pixel at that zoom level. 
	 * These values for "m / pixel" are calculated with an earth radius of 6372.7982 km. 
	 * "Scale" (map scale) is only an approximate size comparison and refers to distances on the equator. 
	 * In addition, the map scale will be dependent on the monitor. 
	 * These values are for a monitor with a 0.3 mm / pixel (85.2 pixels per inch or PPI)
	*/ 
	zoomLevelConvTable : [
	       {zoomLevel: 0,  metriperpixel: 156412,    scaledenom: 500000000},
	       {zoomLevel: 1,  metriperpixel: 78206,     scaledenom: 250000000},
	       {zoomLevel: 2,  metriperpixel: 39103,     scaledenom: 150000000},
	       {zoomLevel: 3,  metriperpixel: 19551,     scaledenom:  70000000},
	       {zoomLevel: 4,  metriperpixel:  9776,     scaledenom:  35000000},
	       {zoomLevel: 5,  metriperpixel:  4888,     scaledenom:  15000000},
	       {zoomLevel: 6,  metriperpixel:  2444,     scaledenom:  10000000},
	       {zoomLevel: 7,  metriperpixel:  1222,     scaledenom:   4000000},
	       {zoomLevel: 8,  metriperpixel:   610.984, scaledenom:   2000000},
	       {zoomLevel: 9,  metriperpixel:   305.492, scaledenom:   1000000},
	       {zoomLevel: 10, metriperpixel:   152.746, scaledenom:    500000},
	       {zoomLevel: 11, metriperpixel:    76.373, scaledenom:    250000},
	       {zoomLevel: 12, metriperpixel:    38.187, scaledenom:    150000},
	       {zoomLevel: 13, metriperpixel:    19.093, scaledenom:     70000},
	       {zoomLevel: 14, metriperpixel:     9.547, scaledenom:     35000},
	       {zoomLevel: 15, metriperpixel:     4.773, scaledenom:     15000},
	       {zoomLevel: 16, metriperpixel:     2.387, scaledenom:      8000},
	       {zoomLevel: 17, metriperpixel:     1.193, scaledenom:      4000},
	       {zoomLevel: 18, metriperpixel:     0.596, scaledenom:      2000},
	       {zoomLevel: 19, metriperpixel:     0.298, scaledenom:      1000} ],
	
	
	/** 
	 * Property: currentDigitizeOperation
	 * {String} Operazione di digitalizzazione corrente ex var wflgpoliadddel.
	 */
	currentDigitizeOperation: '',	

	/** 
	 * Property: digitizeOperationInsert
	 * {String} Operazione di Inserimento-> 'N' .
	 */
	digitizeOperationInsert: 'N',  
	
	/** 
	 * Property: digitizeOperationInsertFromLayer
	 * {String} Operazione di Inserimento da Layer-> 'F' .
	 */
	digitizeOperationInsertFromLayer: 'F', 

	/** 
	 * Property: digitizeOperationInsertFromImport
	 * {String} Operazione di Inserimento da Import-> 'P' .
	 */
	digitizeOperationInsertFromImport: 'P', 
	
	/** 
	 * Property: digitizeOperationVertexEdit
	 * {String} Operazione di VertexEdit -> 'V'.
	 */
	digitizeOperationVertexEdit: 'V',	 

	/** 
	 * Property: digitizeOperationDragDrop
	 * {String} Operazione di DragDrop -> 'R'.
	 */
	digitizeOperationDragDrop: 'R',	

	/** 
	 * Property: operationGeometryModify
	 * {String} Operazione di generica modifica geometria -> 'G' .
	 */
	operationGeometryModify: "G",  

	/** 
	 * Property: digitizeOperationSubtract
	 * {String} Operazione di Subtract -> 'D' .
	 */
	digitizeOperationSubtract: 'D',	

	/** 
	 * Property: digitizeOperationAdd
	 * {String} Operazione di Add -> 'O' .
	 */
	digitizeOperationAdd: 'O',	

	/** 
	 * Property: digitizeOperationAddSub
	 * {String} Operazione di AddSub -> 'M' .
	 */
	digitizeOperationAddSub: 'M',

	/** 
	 * Property: operationFeatureDelete
	 * {String} Operazione di Cancellazione Feature .
	 */
	operationFeatureDelete: 'C',  

	/** 
	 * Property: operationUpdateAlfa
	 * {String} Operazione di Aggiornamento alfanumerico.
	 */
	operationUpdateAlfa: 'A',  

	/** 
	 * Property: operationIdentify
	 * {String} Operazione di Identify .
	 */
	operationIdentify: 'I', 

	/** 
	 * Property: currentSelectedKeys
	 * {String} Chiavi degli oggetti correntemente selezionati per il layer correntemente sotto editing.
	 */
	currentSelectedKeys: null, 

	/** 
	 * Property: bEditingSingoloInsertDone
	 * {} Indica se in modalità di editing singolo e' già stata effettuata la fase di insert.
	 */
	bEditingSingoloInsertDone:null,

	/** 
	 * Property: bEditingSingoloInsertDone
	 * {Boolean} Indica se in modalità di editing singolo e' già stata effettuata la fase di insert.
	 */
	bEditingSingoloInsertDone: false,

	/** 
	 * Property: eventVis
	 * {Number} Costante che indica l'evento di visualizzazione .
	 */
	eventVis: 0,

	/** 
	 * Property: eventCanc
	 * {Number} Costante che indica l'evento di cancellazione.
	 */
	eventCanc: 1,

	/** 
	 * Property: eventUpdateGeom
	 * {Number} Costante che indica l'evento di aggiornamento geometrico .
	 */
	eventUpdateGeom: 2,

	/** 
	 * Property: eventUpdateAlpha
	 * {Number} Costante che indica l'evento di aggiornamento alfanumerico.
	 */
	eventUpdateAlpha: 3,

	/** 
	 * Property: eventIns
	 * {Number} Costante che indica l'evento di inserimento.
	 */
	eventIns: 4, 	

	/** 
	 * Property: eventRicerca
	 * {Number} Costante che indica l'evento di ricerca.
	 */
	eventRicerca: 5,	

	/** 
	 * Property: eventCustomButton
	 * {Number} Costante che indica l'evento di custom button.
	 */
	eventCustomButton: 6,	
	
	/** 
	 * Property: eventInsFromLayer
	 * {Number} Costante che indica l'evento di inserimento prelevando geometria da altro layer.
	 */
	eventInsFromLayer: 7,

	/** 
	 * Property: eventInsFromImprt
	 * {Number} Costante che indica l'evento di inserimento prelevando geometria da import.
	 */
	eventInsFromImport: 8,

	
	/** 
	 * Property: currentSelectedLayer
	 * {} layer corrente (codTPN).
	 */
	currentSelectedLayer: null,

	/** 
	 * Property: selezioneCorrente
	 * {JSGeometryArray} Contiene l'oggetto JSGeometry {@link JSGeometry} attualmente selezionato  oppure null se non e' selezionato niente.
	 */
	selezioneCorrente: new JSGeometryArray(),

	/** 
	 * Property: evidenziazioneCorrente
	 * {JSGeometryArray} Contiene l'oggetto JSGeometry {@link JSGeometry} attualmente evidenziato  oppure null se non e' selezionato niente.
	 */
	evidenziazioneCorrente: new JSGeometryArray(),

	/** 
	 * Property: autoIdentifyCorrente
	 * {JSGeometryArray} 
	 */
	autoIdentifyCorrente: new JSGeometryArray(),

 	/** 
	 * Property: routingCorrente
	 * {JSGeometryArray} Contiene l'oggetto JSGeometry {@link JSGeometry} attualmente evidenziato  oppure null se non e' selezionato niente.
	 */
	routingCorrente: new JSGeometryArray(),
	
	/** 
	 * Property: implicitCustomQuery
	 * {Object} 
	 */
	implicitCustomQuery: new Object(),

	
	/*
	 * 
	 * 
	 * 
	 */
	/**
	 * Property: explicitCustomQueryParams
	 * {Object}
	 * Condizioni esplicite da aggiungere alle chiamate WMS, eventualmente da inserire solo x le chiamate ad alcuni server.
	 * L'oggetto passato deve essere della seguente forma, che ha il seguente significato: aggiunta di param1 con valore val1 per tutti i server,
	 * di chkproc e parametro due per il server che ha SERVERID=WMSLOCALHOST del parametro chkproc per il server che ha SERVERID=RTAMBITIAMM. 
	 * Sono disponibili anche metodi API per la gestione programmatica addExplicitCustomQueryParam, removeExplicitCustomQueryParam, getExplicitCustomQueryParam
	 *     {
		   "param1": 'val1',
		   "WMSLOCALHOST": { "chkproc": chkproc,
							  "parametro2": 'param2'},
		   "RTAMBITIAMM":  { "chkproc": chkproc}
			}															  
														} 
	 */
	explicitCustomQueryParams: {},
	
	/** 
	 * Property: paramsPrev
	 * {} 
	 */
	paramsPrev: null,

	/** 
	 * Property: submitForm
	 * {Ext.form.FormPanel} 
	 */
	submitForm: null,

	// Config parameters
	/** 
	 * Property: paramsJS
	 * {ToloParamsJS}
	 */
	paramsJS: null, 

	/** 
	 * Property: TOLOMEOServer
	 * {String}
	 */
	TOLOMEOServer: null,
	
	/** 
	 * Property: TOLOMEOStaticRoot
	 * {String}
	 */
	TOLOMEOStaticRoot: null,
	

	/** 
	 * Property: TOLOMEOContext
	 * {String}
	 */
	TOLOMEOContext: null,

	/** 
	 * Property: viewer
	 * {TolomeoExt.ToloViewerOLPanel} 
	 */
	viewer: null,

	/** 
	 * Property: viewer3D
	 */
	viewer3D: null,

	viewer3DWidget: null,

	/** 
	 * Property: TOCPanel
	 * {}
	 */
	TOCPanel: null,
	
	tocGuiCreateAction: null,

	/** 
	 * Property: queryPanel
	 * {TolomeoExt.ToloQueryPanelExt}
	 */
	queryPanel: null,
	
 	/** 
	 * Property: olsPanel
	 * {TolomeoExt.OLS.ToloOLSPanelExt}
	 */
	olsPanel: null,
	
	/** 
	 * Property: queryBuilderPanel
	 * {TolomeoExt.ToloQueryBuilderExt}
	 */
	queryBuilderPanel: null,

	/** 
	 * Property: codeLessPanel
	 * {TolomeoExt.ToloCodeLessPanel}
	 */
	codeLessPanel: null,

	/** 
	 * Property: viewCodeLessPanel
	 * {TolomeoExt.ToloVviewCodeLessPanel}
	 */
	viewCodeLessPanel: null,

	/** 
	 * Property: buttonsPanel
	 * {TolomeoExt.ToloButtonPanelExt}
	 */
	buttonsPanel: null,

	/** 
	 * Property: selectedChoiceWindow
	 * {}
	 */
	selectedChoiceWindow: null,

	/** 
	 * Property: autoIdentifyWindow
	 * {}
	 */
	autoIdentifyWindow: null,

	/**
	 * @cfg {TolomeoExt.ToloStylePanel} 
	 * 
	 * Pannello di gestione degli stili (se richiesto)
	 * 
	 */
	stylePanel: null,
	
	/** 
	 * Property: geoOpField
	 * {Ext.form.TextField}
	 */
	geoOpField: null,

	/** 
	 * Property: geoCoordField
	 * {Ext.form.TextField}
	 */
	geoCoordField: null,

	/** 
	 * Property: geoCoordParts
	 * {Ext.form.TextField}
	 */
	geoCoordParts: null,

	
	geomPartsAllFlag: null,
	
	
	/** 
	 * Property: selectedListField
	 * {Ext.form.TextField}
	 */
	selectedListField: null,
	
	/** 
	 * Property: openActionsJS
	 * {String}
	 */
	openActionsJS: null,
	
	/** 
	 * Property: titoloMappa
	 * {String}
	 */
	titoloMappa: 'Mappa di Prato',
	
	/** 
	 * Property: sottotitoloMappa
	 * {String}
	 */
	sottotitoloMappa: null,
	
	/** 
	 * Property: descrizioneMappa
	 * {String}
	 */
	descrizioneMappa: null,
	
	/** 
	 * Property: stampaReferer
	 * {boolean}
	 */
	//stampaReferer: true,
	
	 * Property: urlLogo
	 * Url del logo principale che appare in alto a sinistra nella stampa
	 * {String}
	 */
	urlLogo: "",
	
	/** 
	 * Property: urlLogoSecondario
	 * Url del logo che appare in alto a destra nella stampa
	 * {String}
	 */
	urlLogoSecondario: "",
	
	/**
	 * id dei campi che devono contenere il risultati a fine azione
	 * E' composto da un oggetto di questo tipo
	 * {  	geoOp: "actionEndGeoOp", 
	 *		geoCoord: "actionEndGeoCoord", 
	 *		selectedList: "actionEndSelectedList",
	 *		IDTPN: "actionEndIDTPN",
	 *		codTPN: "actionEndCodTPN"}
	 * @type {Object}
	 */
	actionsEndReturnFields: null,
	
	/** 
	 * Property: temporalFilterDtInizio
	 * {String}
	 */
	temporalFilterDtInizio: null,
	
	/** 
	 * Property: temporalFilterDtFine
	 * {String}
	 */
	temporalFilterDtFine: null,
	
	/** 
	 * Property: permalinkParameterSuffix
	 * Suffisso da utilizzare per recuperare o costruire i lnome dei parametri del permalink
	 * {String}
	 */
	permalinkParameterSuffix: null,
	
	autoCloseChoiceWindow: true,
	
	wmsExplorerWidget: null,
	
	cswWidget: null,
	
	/**
	 * Property: projectionCrs
	 * {Obect} Specifica i sistemi di riferimento da utilizzare nella riproiezione (vedi Mostra Coordinate)
	 */
	
	
	/*'EPSG:26591':{precision: 2, description: 'Gauss Boaga [26591]'},*/
	projectionCrs: {'EPSG:25832': {precision: 2, description: 'ETRS89 / UTM zone 32N [25832]'},
					'EPSG:6707':  {precision: 2, description: 'RDN2008 / UTM zone 32N [6707]'},
					'EPSG:3003':  {precision: 2, description: 'Gauss Boaga [3003]'},
					'EPSG:4326':  {precision: 7, description: 'WGS84'}},
	
	contextMenu: null,
	
	statusPanel: null,
	
	// Separatore utilizzato per separare stringe di layer e stili
	layerStringSeparator: ',',
   
	/**
	 * Constructor: TolomeoExt.ToloMapAPIExt
	 * Create a new TolomeoExt.ToloMapAPIExt
	 * 
	 *  Parameters:
	 *  config - {Object} La configurazione
	 *  
	 *  Returns:
	 *  {<TolomeoExt.ToloMapAPIExt>} A new TolomeoExt.ToloMapAPIExt
	 */
	constructor: function(config) {

		me = this;
		Ext.apply(this, config);
	    
		// Assegna un id casuale
		this.apiid = 'tolomeoapi-' + Math.floor((Math.random() * 100000) + 1);
		
		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
        TolomeoExt.applyIfEmpty(this, {
        	actionsEndReturnFields: {
        		geoOp:        "actionEndGeoOp", 
				geoCoord:     "actionEndGeoCoord", 
				selectedList: "actionEndSelectedList",
				IDTPN:        "actionEndIDTPN",
				codTPN:       "actionEndCodTPN"
			},
        	temporalFilterDtInizio: "01/01/0001",
        	temporalFilterDtFine  : "31/12/9999"
		});
		
        this.callParent(arguments);
	 
        
		this.bEditingSingoloInsertDone = false;
		
		// Definisco eventi 
	    this.addEvents('onOperationEnable');   		 // passa codice operazione da abilitare
	    this.addEvents('onOperationDisable');		 // passa codice operazione da disabilitare
	    this.addEvents('onOperationPressDefault');	 // passa codice gruppo di cui premere default
	    this.addEvents('onObjectSelect'); 			 // oggetto selezionato utilizando lo strumento di selezione
	    
	    this.addEvents('onBeforeClearSelected'); 	 // prima che la selezione corrente sia cancellata (svuotata). PAssa i parametri , bRedraw, codTPN, bClearUrl
	    this.addEvents('onAfterClearSelected'); 	 // dopo che la selezione corrente cancellata (svuotata). PAssa i parametri , bRedraw, codTPN, bClearUrl
	    this.addEvents("actionsEnd"); 				 // lanciato a fine azioni, passa un oggetto contenente geoOp, geoCoord etc. 
	    this.addEvents("digitizedFeatureModifyEnd"); // Eseguita quando una feature digitalizzata viene in un secondo momento modificata
		this.addEvents("onEventActionAjaxSuccess");  // Evento lanciato quando una azioneevento conclude con successo una chiamata ajax.L'evento viene chiamato con i seguenti parametri
													 // eventoLayer, tipoEvento, idBtn, nStep, records, store. 
													 // Se la chiamata non è crossDomain records contiene trasport della chiamata normale e store non c'e'
													 // Utilizzare con codice come il seguente
													 // function a(eventoLayer, tipoEvento, idBtn, nStep, records, store) {
													 //     alert("ale");
													 //	}
													 // function apriMappa(codici) {
													 //	tolomeo = new TolomeoExt.ToloPanelIntra({
													 //		withDataPanel: true,
													 //		withToolsPanel: false,
													 //		APIConfig: {
													 //			listeners: {
													 //       	 		onEventActionAjaxSuccess: {
													 //								fn: a
													 //							      }
													 //				}
													 //			}
													 //	});
	    this.addEvents("onEventActionAjaxFailure");
	    this.addEvents("beforeOpenUrl");			// Evento lanciato prima di una openURL (apertura di url su un certo target alla fine di una azione)
	    this.addEvents("openUrl");					// Evento lanciato alla fine di una openURL (apertura di url su un certo target alla fine di una azione)
	                                                // Parametri: url e target 
	    
	    this.addEvents("beforeClearUrl");			// Evento lanciato prima di una clearURL 
	    this.addEvents("clearUrl");					// Evento lanciato alla fine di una clearURL
	                                                // Parametri: url e target 
	    this.addEvents("visualize");				// Evento lanciato quando viene richiesto di visualizzare i dati di un oggetto. Vengono passati in automatico codTPN e IDTPN
	    this.addEvents("selectRequestBeforeStart"); // Evento lanciato prima di fare la richiesta per recuperare una selezione
	    this.addEvents("selectRequestStart");       // Evento lanciato quando la richiesta per recuperare una selezione è partita
	    this.addEvents("selectRequestEnd");			// Evento lanciato quando la richiesta per recuperare una selezione è finita. Viene passato l'oggetto con l'esito, il numero di risultati ed il messaggio di errore.
	    this.addEvents("tocGuiCreate");	    
	    
	    this.addEvents("afterContextMenuCreate");   // Evento lanciato dopo che il menu di contesto è stato creato
	    this.addEvents("j2qConnected");             // Evento lanciato doop che si è verificata una connessione con il plugin J2Q di QGis
	    this.addEvents("selectedObjectsRemoved");   // Evento lanciato quando vengono rimossi oggetti dalla selezione. Viene passata la lista degli oggetti rimossi e l'ultimo oggetto rimasto in selezione corrente.
	    
	    this.addEvents("previousNavigationStateAvailable");		// Evento lanciato quando è disponibile lo stato di navigazione mappa precedente
		this.addEvents("previousNavigationStateNotAvailable");	// Evento lanciato quando non è disponibile lo stato di navigazione mappa precedente
		this.addEvents("nextNavigationStateAvailable");       	// Evento lanciato quando è disponibile lo stato di navigazione mappa successivo
		this.addEvents("nextNavigationStateNotAvailable");		// Evento lanciato quando non è disponibile lo stato di navigazione mappa successivo
	    
		this.addEvents("digitizeEnd");				// Evento lanciato quando finisce la digitalizzazione di una geometria, passa la gemetria stessa
		this.addEvents("digitizeEndInsert");		// Evento lanciato quando finisce la digitalizzazione di una geometria per funzione di insert (nuova geometria), pass la gemetria stessa
		
		this.addEvents("digitizeEndAdd");			// Evento lanciato quando finisce la digitalizzazione di una geometria per funzione di Add passa la gemetria stessa
		this.addEvents("digitizeEndVertexEditing");	// Evento lanciato quando finisce la digitalizzazione di una geometria per funzione di vertezediting, passa la gemetria stessa
		this.addEvents("digitizeEndDragDrop");		// Evento lanciato quando finisce la digitalizzazione di una geometria per funzione di dragdrop, passa la gemetria stessa
		this.addEvents("digitizeEndSubtract");		// Evento lanciato quando finisce la digitalizzazione di una geometria per funzione di subtract, passa la gemetria stessa
		this.addEvents("digitizeEndAddSub");		// Evento lanciato quando finisce la digitalizzazione di una geometria per funzione di addsub, passa la gemetria stessa

		
	    this.geoOpField = Ext.create('Ext.form.TextField', {
	    	name: 'geoOp'
	    });
	    							
	    this.geoCoordField = Ext.create('Ext.form.TextField', {
	    	name: 'geoCoord'
	    });
	    
	    this.geoCoordParts = Ext.create('Ext.form.TextField', {
	    	name: 'geoParts'
	    });
	    
	    this.geomPartsAllFlag = Ext.create('Ext.form.TextField', {
	    	name: 'geomPartsAllFlag'
	    });
	    
	    
	    							
		this.selectedListField = Ext.create('Ext.form.TextField', {
			name: 'selectedList'
		});
		
	    this.submitForm = Ext.create('Ext.form.FormPanel', {
			hidden: true,
			renderTo: Ext.getBody(),
			bodyStyle: 'position:absolute; top: 0px; left 0px;',
			standardSubmit: true,
			method: 'POST',
			items: [this.geoOpField, this.geoCoordField, this.geoCoordParts, this.geomPartsAllFlag, this.selectedListField]
	    });
		
		this.bindToViewerPanel();
		this.bindToButtonsPanel();
		this.bindToQueryPanel();
		this.bindToOLSPanel();
		this.bindToTOCPanel();
		this.bindToStylePanel();
		this.bindToContextMenu();
		this.bindToStatusPanel();
		
		// ///////////// //
		// QUERY BUILDER //
		// ///////////// //
		this.bindToQueryBuilderPanel();
		
		// ///////////// //
		// CODELESS FORM //
		// ///////////// //
		this.bindToCodeLessPanel();
		this.bindToViewCodeLessPanel();
		
		// TODO Collegare setCurrentLayer all'evento di cambio layer su combo
		
		// TODO Definire eventuali  eventi
		//this.addEvents('permittedOperationsChange'); // TODO Fire
	
		//this.callParent(arguments);
		
		
		// vecchia funzione initTolomeo inizio 
		// this.doOpenActions();
	   	
		//TODO NB: Questi eventi vengono intercettati con successo solo se il layout tolomeo che estende toloPanelBase è incluso in un pannello e non utilizzato direttamente. 
		// Questo perchè nel secondo caso quando arriva qua gli eventi sul viewer sono gia stati lanciati. 
	   	this.viewer.on('onAfterPreInit', function()   { this.applyCustomQuery(); }, this, {single: true});  //this.map.render(this.mapPanel.body.dom);},this,{single: true});
		this.viewer.on('onBeforePostInit', function() { this.doOpenActions(); this.doOpenActionsJS(); },  this, {single: true});  //this.map.render(this.mapPanel.body.dom);},this,{single: true});

	
		// le operazioni consentite potrebbero essere in funzione delle openActions (come per esempio in caso di editSingolo)
		this.togglePermittedOperations();	
		
		// Disegno la mappa
		//this.applyCustomQuery();
		
		// postinizializzazione viewer
		//if (this.viewer) this.viewer.pluginPostInit(this.paramsJS);
	
		// Inizializzazione eventuale legenda
		//if (this.viewer!=null) {
		//	if (this.TOCPanel!=null) {
		//		this.TOCPanel.showTOC(this.viewer.pluginGetCurrentZoom());
		//	}
		//}
		// vecchia funzione initTolomeo fine
		
		htmlInfoTolomeoWin = 
			"<center>" +
			"<b>Comune di Prato</b>" +
			"<br/>" +			
			"<b>Tolomeo versione " + TolomeoExt.Vars.TOLOMEOVersion + "</b>" +
			"</center>" +
			"<br/>" +
			"<b>Sito di riferimento</b><br/>" +
			"<a href=\"http://tolomeogis.comune.prato.it\" target=\"_blank\">http://tolomeogis.comune.prato.it</a>"+
			"<br/>" +
			"<br/>" +
			"<b>Librerie utilizzate</b><br/>" +
			"<b><i>Java</i></b><br/>" +
			"SIT core " + this.paramsJS.sitCoreVersion + "<br/>" +			
			"<b><i>Javascript</i></b><br/>" +
			"ExtJS " + Ext.getVersion() + "<br/>" +
			"OpenLayers " + OpenLayers.VERSION_NUMBER + "<br/>" +
			(((typeof Cesium !== "undefined")) ? "Cesium " + Cesium.VERSION + "<br/>" : "") +
			"<br/>" +
			"<b>Sviluppatori</b>" +
			"<br/>" +
			"Alessandro Radaelli" +
			"<br/>" +
			"Federico Nieri" +
			"<br/>" +
			"Mattia Gennari";
			
			//"<b>Copyright Ortofoto</b><br/>" +
			//"&copy; Copyright Regione Toscana - ofc anno 2010<br/>" +
			//"&copy; Copyright Regione Toscana - ofc 1:2.000 anno 2009<br/>" +
			//"&copy; Copyright Regione Toscana - ofc anno 2004 <br/>" +
			//"&copy; Copyright Regione Toscana - ofc anno 1998 <br/>";
			
			
		this.tolomeoInfoWin = new Ext.Window({
			
			title: 'Tolomeo',
			bodyStyle: 'padding: 0px',
			cls: 'clearCSS',
			width: 550,
			height: 450,			
			modal: true,
			closeAction: 'hide',
			constrain: true,
			layout: 'fit',
			buttons: [{
	        	text: ToloI18n.getMsg("ToloMapAPIExt.tolomeoInfoWin.btnChiudi.text"),
	       		listeners: {click: {fn: function() {
	       			this.tolomeoInfoWin.hide();
	       		},scope: this}}	       		
	        }],
	        items : {
	        	xtype : 'tabpanel',
	        	activeItem : 0,
	        	minTabWidth : 120,
    			tabWidth    : 135,
    			enableTabScroll: true,
    			border: false,
    			defaults: {
    				xtype: 'panel',
    				layout: 'fit',
    				autoScroll: true
    			},
    			items: [{
    				title: ToloI18n.getMsg("ToloMapAPIExt.tolomeoInfoWin.tabInfo.title"),
    				html: htmlInfoTolomeoWin,
    				bodyStyle: 'padding:10px;font-size:12px;line-height:150%',
    				frame: false,
    				border: false,
    				plain: true
    			},{
    				title: ToloI18n.getMsg("ToloMapAPIExt.tolomeoInfoWin.tabLicenza.title"),
    				autoScroll: false,    				
    				items: [{
						xtype : 'box',
						id : 'licenseTolomeo',						
						autoEl : {
							tag : 'iframe',
							style : 'border-width: 0px;font-size: 10px',
							src : this.TOLOMEOServer + this.TOLOMEOStaticRoot + '/html/license.html'
						}
					}]
					
    			}]
	        }
		});
		
		
		this.tocInfoField = new Ext.form.TextField({
	    	name: 'tocInfo'
	    });
	    							
	    this.paramsJSField = new Ext.form.TextField({
	    	name: 'paramsJS'
	    });
		
		this.nMappaField = new Ext.form.TextField({
			name: 'nMappa'
		});
		
		this.idxCategoriaBase = new Ext.form.TextField({
			name: 'idxCategoriaBase'
		});
		
		this.idxLayerBase = new Ext.form.TextField({
			name: 'idxLayerBase'
		});

	    this.exportForm = new Ext.form.FormPanel({
			hidden: true,
			renderTo: Ext.getBody(),
			//bodyStyle: 'position:absolute; top: 0px; left 0px;',
			standardSubmit: true,
			method: 'POST',
			defaults: {
				xtype: 'hiddenfield'
			},
			items: [{	
					name: 'tocInfo'
				},{
					name: 'paramsJS'
				},{
					name: 'nMappa'
				},{
					name: 'idxCategoriaBase'
				},{
					name: 'idxLayerBase'
			},{
					name: 'version'
			}]
	    });		
	    
	    Ext.onReady(function(){
	    
	    	var j2qRunner = new Ext.util.TaskRunner();				
			var j2qTask = j2qRunner.newTask({
				
			    run: function(){ 
			    	if(window.JSTOQGIS_INTERFACE){		
			    		j2qTask.stop();
		    			j2qTask.destroy();
		    			me.bindToJ2Q();	            
		    			me.fireEvent('j2qConnected');
			    	} 
			    }, 
			    interval: 250,
			    repeat: 40,
			    scope: this
			});		
			
			j2qTask.start();
				
	    });
		
	},
	
	bindToJ2Q: function(){
		
		this.QGisConnected = true;
		
		var j2qBtn = Ext.getCmp('qgisConnection');
		if(j2qBtn){
			j2qBtn.setVisible(true);
		}
		Ext.MessageBox.show({
			title: ToloI18n.getMsg("ToloMapAPIExt.QGisConnection.title"),
            msg: ToloI18n.getMsg("ToloMapAPIExt.QGisConnection.msg"), 
            width:300,				                
            animateTarget: j2qBtn?'qgisConnection':null,
            iconCls : 'iconConnected2QGis'
        });
        setTimeout(function(){
        	Ext.MessageBox.hide();				                 
        }, 2500);
        
	},
	
	/**
	  * Method: bindToTOCPanel
	  * 
	  */
	bindToTOCPanel: function() {
		
		if (this.TOCPanel!=null) {			
			
			if(this.TOCPanel.isTOCCreated){
				if(this.buttonsPanel) this.buttonsPanel.switchTocRelatedButtons(true,true);
				this.attributionsChange();
			} else {
				this.TOCPanel.on('tocCreate', function() { 
					if(this.buttonsPanel) this.buttonsPanel.switchTocRelatedButtons(true,true);
					this.attributionsChange();
				}, this);
			}
			
			this.relayEvents(this.TOCPanel,['tocGuiCreate']);
			this.TOCPanel.on('afterrender', function() { 
				if (this.viewer.isAlreadyDrawn) {
					this.TOCPanel.createOrUpdate(this.viewer.pluginGetCurrentZoom()); 
				}
			}, this);

			this.TOCPanel.on('layerOpacityChange', this.setLayerOpacity, this);
			this.TOCPanel.on('layerEnhanceChange', this.setLayerEnhance, this);
			
			
			this.TOCPanel.on('layerCheckedChange', function(layer){
				if(layer.checked) return;
				var removedGeoms = [];
				if(layer.codTPN && !this.TOCPanel.layerIsVisible(layer.codTPN)){
					removedGeoms.push(this.clearSelected(false,layer.codTPN));
					if(this.selezioneCorrente.size()>0){
						//this.fireEvent('onObjectSelect', this.selezioneCorrente.getByIndex(this.selezioneCorrente.size()-1));
						this.fireEvent('selectedObjectsRemoved',removedGeoms, this.selezioneCorrente.getByIndex(this.selezioneCorrente.size()-1));
					}
				}
			}, this);
			this.TOCPanel.on('categoryCheckedChange', function(category, tocInfo){				
				if(category.checked) return;
				var removedGeoms = [];
				
				tocInfo.onEachLayer(function(cat,lay,catIdx,layIdx){
					if(lay.codTPN && !this.TOCPanel.layerIsVisible(lay.codTPN)){
						removedGeoms.push(this.clearSelected(false,lay.codTPN));
					}
				},this,category.catTreeIdx,true);
				
				if(this.selezioneCorrente.size()>0){
					this.fireEvent('selectedObjectsRemoved',removedGeoms, this.selezioneCorrente.getByIndex(this.selezioneCorrente.size()-1));
				}
			}, this);
			
			this.on('onObjectSelect',function(geoms){
				var geom = geoms.geometries?geoms.geometries[0]:geoms;
				this.TOCPanel.setLayerVisibility(geom.codTPN);
			},this);	
									
			this.TOCPanel.on('stylePanelRequest', this.mostraStylePanel, this);

			this.TOCPanel.on('contextMenuZoomToExtent', this.TOCContextMenuZoomToExtent, this);
			
			this.TOCPanel.on('contextMenuShowInfo', this.TOCContextMenuShowInfo, this);
			this.TOCPanel.on('contextMenuZoomMaxScaleMax', this.TOCContextMenuZoomScaleMax, this);
			this.TOCPanel.on('contextMenuZoomMinScaleMin', this.TOCContextMenuZoomScaleMin, this);
			this.TOCPanel.on('contextMenuMetadataClick', this.showMetadata, this);
			
			
			this.TOCPanel.on('itemClicked', this.TOCItemClicked, this);		
			this.TOCPanel.on('exportForQgisClicked', function (catIdx, layIdx, version) { this.exportForQgis(catIdx, layIdx, version); }, this);
			
			
			this.on('j2qConnected',function(geoms){
				if(this.TOCPanel.isTOCCreated){
					this.TOCPanel.enableJ2QFeatures();			
				} else {
					this.TOCPanel.on('tocCreate', function() { 
						this.TOCPanel.enableJ2QFeatures();
					}, this);
				}
				
			},this);
			
			this.TOCPanel.on('addLayerToQgisClicked', this.addLayerToQGis, this);		
			
		} else {
			if(this.buttonsPanel) this.buttonsPanel.switchTocRelatedButtons(false,true);
		}
	},
	
	TOCContextMenuZoomToExtent: function (cat, lay, tocInfo) {
		
		var bbox = tocInfo.getBoundingBox(cat, lay) ;
		if (bbox!=null) this.zoomToExtent(bbox, 0);
			
	},
	
	TOCContextMenuShowInfo: function (cat, lay, tocInfo) {
		
		if (lay!=undefined && lay!=null) {
			var layInfo = tocInfo.getCategoryInfo(cat).layers[lay];
			var info = layInfo.layerAbstract;
			
			if (info && info!="") {
			
				var idwin = this.id+'-contextmenushowinfo'+Math.random();
				
				Ext.create('Ext.Window',{
					id: idwin,
					title: ToloI18n.getMsg("ToloMapAPIExt.TOCContextMenuShowInfo.win.title", {LAYDESCR: layInfo.descr}),
					layout: 'fit',
					//iconCls: 'iconPrint',
					frame: true,
					border: true,
					maximizable: true,
					autoScroll:  true,
					//monitorResize: true,
					//plain: true,
					modal: false,
					width: 300,
					height: 150,
					cls: 'clearCSS',
					html: layInfo.layerAbstract,
					buttonAlign: 'right',
					buttons: [{
			            text: ToloI18n.getMsg("ToloMapAPIExt.TOCContextMenuShowInfo.btnChiudi.text"),
			            width: 75,
			            listeners: { click: { fn: function() { Ext.getCmp(idwin).close(); } } }
			        	}]
				}).show();
			} else {
				Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.TOCContextMenuShowInfo.msgNoInfo.title"),
						ToloI18n.getMsg("ToloMapAPIExt.TOCContextMenuShowInfo.msgNoInfo.msg"));
			}
		} else {
			Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.TOCContextMenuShowInfo.msgNoInfo.title"),
					ToloI18n.getMsg("ToloMapAPIExt.TOCContextMenuShowInfo.msgNoInfo.msg"));
		}
			
	},

	TOCContextMenuZoomScaleMin: function(cat, lay, tocInfo, scalaminmax) {
		/*
		 *var layInfo = tocInfo.getCategoryInfo(cat).layers[lay];
		
		if (layInfo!=null) {
			// imposto un poco di margine per tenere conto che mapserver ha dpi interi quindi è impostato 91 invece di 90.74 e considero un poco di margine
			var s = layInfo.minScaleMin * 1.01;
			// Scelgo una scala arrontondata a 10 (meno brutta da vedere)
			s = Math.floor(s/10+1) * 10;
			this.zoomToScale(s);
		}*/
		
		var scala = scalaminmax.scalaMinima;
		if (scala!=null) {
			// imposto un poco di margine per tenere conto che mapserver ha dpi interi quindi è impostato 91 invece di 90.74 e considero un poco di margine
			var s = scala * 1.01;
			// Scelgo una scala arrontondata a 10 (meno brutta da vedere)
			s = Math.floor(s/10+1) * 10;
			this.zoomToScale(s);
		}
		
	},
	
	TOCContextMenuZoomScaleMax: function(cat, lay, tocInfo, scalaminmax) {
		/*
		var layInfo = tocInfo.getCategoryInfo(cat).layers[lay];
		
		if (layInfo!=null) {
			// imposto un poco di margine per tenere conto che mapserver ha dpi interi quindi è impostato 91 invece di 90.74 e considero un poco di margine
			var s = layInfo.maxScaleMax * 0.99;
			// Scelgo una scala arrontondata a 10 (meno brutta da vedere)
			s = Math.floor(s/10) * 10;
			this.zoomToScale(s);
		}
		*/
		
		var scala = scalaminmax.scalaMassima;
		if (scala!=null) {
			// imposto un poco di margine per tenere conto che mapserver ha dpi interi quindi è impostato 91 invece di 90.74 e considero un poco di margine
			var s = scala * 0.99;
			// Scelgo una scala arrontondata a 10 (meno brutta da vedere)
			s = Math.floor(s/10) * 10;
			this.zoomToScale(s);
		}
	},
	
	showMetadata: function(metadata) {
		
		var iframe = Ext.create('TolomeoExt.ToloIFrame', {
			frameName: 'metadata',
			url: metadata.url
		});
		Ext.create('Ext.Window', {
			layout: 'fit',
			title: ToloI18n.getMsg("ToloButtonPanelExt.mnuGuida.text", {TIPO:  metadata.type}),
			maximizable: true,
			constrain: true,
			width: 600,
			height: 500,
			items: [iframe]
		}).show();
		
	},
	
	TOCItemClicked: function(catTreeIdx, layTreeIdx, classi, e) {
	
		// TODO Supportata solo mappa 0
		var mappa = this.paramsJS.mappe.mappaList[0];
		
    	if (catTreeIdx && layTreeIdx && !classi ) {
	    	
    		var currCat = this.TOCPanel.tocInfo.getCategoryInfo(catTreeIdx);
			var currLayer =  currCat.layers[layTreeIdx];	
    		
			// Verifica se è definito un link e se l'elemento clickato è un anchor
	    	if (currLayer.clickUrl && e.target.nodeName.toUpperCase()=="A") {
	    		var params = "";
	        	params += (currLayer.codTPN) ? "codTPN=" + currLayer.codTPN : "";
	        	params += ((params!="") ? "&" : "") + "catIdx=" + encodeURIComponent(currLayer.catTreeIdx);  
	        	params += "&layIdx=" + encodeURIComponent(currLayer.layTreeIdx);
	       
	        	// {left: XXX, bottom: XXXXX, right: XXX, top: XXX};
	        	var extent = this.viewer.pluginGetMapExtent();
	        	// tolobbox=x1:x2:y1:y2 che sarebbe il box in coordinate , separate da carattere ":" della mappa nel momento in cui si cliccka su un layer.
	        	params += "&tolobbox=" + extent.left + ":" + extent.right + ":" + extent.bottom + ":" + extent.top;
	        	
	        	// tolosrid
				params += "&tolosrid=" + encodeURIComponent(this.paramsJS.mappe.SRID);
	       
	       		// tolozoom=xxxxx dove xxxxx è il denominatore: se la scala e' 1:12345  sarebbe ...&zoom=12345
				params += "&tolozoom=" + this.viewer.pluginGetCurrentZoom();
	       
				var currCatPreset = this.TOCPanel.tocInfo.getCategoryPresetInfo(catTreeIdx);
				var currLayerPreset =  currCatPreset.layerList[layTreeIdx];
				var server = this.paramsJS.getServer(currLayerPreset.serverID, mappa);
				
				if (server) {
					// tololayerserver
					params += "&tololayerserver=" + encodeURIComponent(server.url);
		       
					// tololayername
		       		params += "&tololayername=" + encodeURIComponent(currLayerPreset.name);
				}	
	        	var retVal = currLayer.clickUrl;
	        	if (params!="") {
	        		retVal += ((retVal.indexOf("?")==-1) ? "?" : "&")  + params ;	
	        	} 
	     		
	        	this.openURL(retVal, currLayer.clickTarget);
	    	}
    	} else if ( catTreeIdx && layTreeIdx==null && !classi){
    		var currCat = this.TOCPanel.tocInfo.getCategoryInfo(catTreeIdx);
			
	    	if (currCat.clickUrl) {
	    		var params = "";
	        	params += "catIdx=" + encodeURIComponent(currCat.catTreeIdx);  
	        	
	        	// {left: XXX, bottom: XXXXX, right: XXX, top: XXX};
	        	var extent = this.viewer.pluginGetMapExtent();
	        	// tolobbox=x1:x2:y1:y2 che sarebbe il box in coordinate , separate da carattere ":" della mappa nel momento in cui si cliccka su un layer.
	        	params += "&tolobbox=" + extent.left + ":" + extent.right + ":" + extent.bottom + ":" + extent.top;
	        	
	        	// tolosrid
				params += "&tolosrid=" + encodeURIComponent(this.paramsJS.mappe.SRID);
	       
	       		// tolozoom=xxxxx dove xxxxx è il denominatore: se la scala e' 1:12345  sarebbe ...&zoom=12345
				params += "&tolozoom=" + this.viewer.pluginGetCurrentZoom();
	       
	        	var retVal = currCat.clickUrl;
	        	if (params!="") {
	        		retVal += ((retVal.indexOf("?")==-1) ? "?" : "&")  + params ;	
	        	} 
	     		
	        	this.openURL(retVal, currCat.clickTarget);
	    	}
    	}
		
	},
	
	/**
	 * Mostra il pannello di gestione degli stili
	 * 
	 * @param {String} nome del layer
	 * @param {Number} numero categoria del layer 
	 * @param {Number} numero del layer
	 * @param {String[][]} Elenco degli stili definiti per il layer nella forma [['stile1'],['stile2']] 
	 */ 
	 mostraStylePanel: function(layer, cat, lay, definedStyles) {
		
		if (this.stylePanel) {
			this.stylePanel.mostra(layer, cat, lay, definedStyles);	
		}
		
	},
	
	/**
	 * Nasconde il pannello di gestione degli stili
	 * 
	 */
	nascondiStylePanel: function() {
		
		if (this.stylePanel) this.stylePanel.nascondi();
		
	},
	
	/**
	 * Method: setLayerOpacity
	 * Metodo per impostare l'opacità del layer. 
	 *
	 * Parameters:
	 * nomeLayer - {} il nome del layer.
	 * newValue - {} il nuovo valore.
	 */
	setLayerOpacity: function (catIdx, layIdx, newValue, oldValue, tocInfo  ) {
		 
		 
		// Se il layer era totalmente opaco o se lo diventa occorre ricalcolare i raggruppamenti
		if ((newValue!=1 && oldValue==1) ||
			(oldValue!=1 && newValue==1)) {
	
			// Ricrea la mapDefinition a partire dalle info di tocInfo (quindi con nuovo valore di trasparenza)
			this.viewer.pluginRemoveAllLayers();
			this.paramsJS.createMapDefinition(tocInfo);
			this.viewer.pluginAddAllMaps();
		} else {
			// ... altrimenti è solo un cambio di opacità senza ricalcolo gruppo
			// TODO gestisce solo mappa 0
			var layAgg = this.paramsJS.mapDefinitions[0].whichLayerAggregationContains(catIdx, layIdx);
			layAgg.opacity = newValue;
			this.viewer.pluginSetLayerOpacity(layAgg.nPluginLayer, newValue);
		} 
			
		if (this.viewer3D) {
			this.viewer3D.removeAllLayers();
			this.viewer3D.addAllLayers();	
		} 
	},
	
	/**
	 * @method setLayerEnhance
	 * Metodo per impostare il miglioramento immagine del layer. 
	 *
	 * Parameters:
	 * @param effect 
	 * @param catIdx
	 * @param layIdx
	 * @param newValue
	 * @param oldValue
	 * @param tocInfo
	 * 
	 */
	setLayerEnhance: function (effect, catIdx, layIdx, newValue, oldValue, tocInfo  ) {
		 
		 
		// Se il layer era in uno stato diverso dal default o lo diventa o se lo diventa occorre ricalcolare i raggruppamenti
		if ((newValue!=effect.defaultValue && oldValue==effect.defaultValue) ||
			(oldValue!=effect.defaultValue && newValue==effect.defaultValue)) {
	
			// Ricrea la mapDefinition a partire dalle info di tocInfo (quindi con nuovo valore di trasparenza)
			this.viewer.pluginRemoveAllLayers();
			this.paramsJS.createMapDefinition(tocInfo);
			this.viewer.pluginAddAllMaps();
		} else {
			var layAgg = this.paramsJS.mapDefinitions[0].whichLayerAggregationContains(catIdx, layIdx);
			layAgg[effect.key] = newValue;
			this.viewer.pluginSetLayerEnhance(effect, layAgg.nPluginLayer, newValue);
		} 
		if (this.viewer3D) {
			this.viewer3D.removeAllLayers();
			this.viewer3D.addAllLayers();	
		} 
	},
	
	

 	/**
     * Method: bindToQueryPanel
     * 
     */
	bindToQueryPanel: function() {

		if (this.queryPanel!=null) {
			this.queryPanel.on('queryMultipleResultHoverStart', this.addHighlighted, this);
			this.queryPanel.on('queryMultipleResultOut', this.clearHighLigthed, this);
			
			this.queryPanel.on('geomFilterFieldCreated', this.queryPanelSetGeomField, this);
			
			this.queryPanel.on(
				'querySelected',
				function(geoms) { 
					var geom = geoms.geometries[0]; 						
					var selectable = this.paramsJS.isSelectable(geom.codTPN);
					
					//senza redraw perchè faceva chiamate fantasma.
					if(selectable){
						this.clearSelected(false); 
						this.addSelected(geom); 
						this.zoomToSelected(null,200);																	
					}else{						
						this.clearHighLigthed(false);
						this.addHighlighted(geom); 
						this.zoomToHighlighted(null,200);
					}
					
					if(this.QGisConnected){						
						JQ.AddWKTLayer(geom.geometry,geom.description,this.getProjectionCode(),{}, false);			
						var bbox = selectable ? this.viewer.pluginGetSelectedFeaturesBounds(200) : this.viewer.pluginGetHighlightedFeaturesBounds(200);
						var epsg = this.getProjectionCode().substring(5);
						
						setTimeout(function(){
				        	// Ext.Msg.alert('Faccio lo zoom','EPSG = ' + epsg + '<br>QGis version = ' + JQ.GetQgisVersion());
							JQ.ZoomToExtent(bbox.left,bbox.bottom,bbox.right,bbox.top,epsg);				                 
				        }, 2000);
        						
					}
					
					/*
					var selLayer = this.getCurrentSelectLayer();
					if (selLayer!=null) {
						if (selLayer.azioniEventiVis.autoVisOnSelect) {
							var layer = this.paramsJS.getParamJSLayer(geoms.geometries[0].codTPN);
							//this.setCurrentSelectLayer(geoms.geometries[0].codTPN);
							this.identify(layer);
						}
					}
					*/
				}, 
				this
			);
		}
	},

	/**
	 * Method: bindToOLSPanel
	 * 
	 */
	bindToOLSPanel: function() {
		if (this.olsPanel!=null) {
			this.olsPanel.on("addressSelected", function(street, lon, lat, crs, zoomLevel) {
				this.gotoPosition(lon, lat, zoomLevel, false, crs);
				var htmlText = "<div style='font: 11px tahoma,arial,helvetica,sans-serif;'><b><u>" + street + "</u></b><br></div>";
				this.addPopup(lon, lat, htmlText, false, false);
			}, this);
			this.olsPanel.on("startAddressSelected", function(street, lon, lat, crs, zoomLevel) {
				this.addStartRoutingMarker(lon, lat, crs);
				this.gotoPosition(lon, lat, zoomLevel, false, crs);
			}, this);
			this.olsPanel.on("endAddressSelected", function(street, lon, lat, crs, zoomLevel) {
				this.addEndRoutingMarker(lon, lat, crs);
				this.gotoPosition(lon, lat, zoomLevel, false, crs);
			}, this);
			this.olsPanel.on("viaAddressAdded", function(viaId, street, lon, lat, crs, zoomLevel) {
				this.addViaRoutingMarker(viaId, lon, lat, crs);
				this.gotoPosition(lon, lat, zoomLevel, false, crs);
			}, this);
			this.olsPanel.on("routeReceived", function(routeResponse) {
				this.addRouting(routeResponse, false);
					this.zoomToRouting();
			}, this);
			this.olsPanel.on("navigationSelected", function(instruction, crs, zoomLevel) {
				this.viewer.pluginZoomToInstruction(instruction.geometry, zoomLevel);
			}, this);
			this.olsPanel.on("navigationFocus", function(instruction, crs) {
				//this.addHighlighted(instruction.geometry, false);
				this.viewer.pluginRoutingInstructionHighlight(instruction, true);
			}, this);
			this.olsPanel.on("navigationBlur", function(instruction, crs) {
				//this.clearHighLigthed(false);
				this.viewer.pluginRoutingInstructionHighlight(instruction, false);
			}, this);
			this.olsPanel.on("viaPointSelected", function(viaId, street, lon, lat, crs, zoomLevel) {
				this.gotoPosition(lon, lat, zoomLevel, false, crs);
			}, this);
			this.olsPanel.on("viaPointsChanged", function(viaPoints) {
				this.setViaRoutingMarkers(viaPoints, this.paramsJS.mappe.SRID);
			}, this);
				this.olsPanel.on("reset", function() {
				this.clearRouting();
				this.viewer.pluginClearStartRoutingMarker();
				this.viewer.pluginClearEndRoutingMarker();
				this.viewer.pluginClearViaRoutingMarkers();
			}, this);
			
			if (this.viewer) {
				this.viewer.on('startPointMoved', this.olsPointMoved, this);
				this.viewer.on('endPointMoved', this.olsPointMoved, this);
				this.viewer.on('viaPointMoved', this.olsPointMoved, this);
				
				this.viewer.on('routingInformationSelect', 
							function(instructionId) {
								this.olsPanel.routingInformationSelect(instructionId);
							}, this);
				this.viewer.on('routingInformationUnSelect', 
							function(instructionId) {
								this.olsPanel.routingInformationDeSelect(instructionId);
							}, this);
				
			}
		}
	},
	
	/**
	 * Method: olsPointMoved
	 * 
	 */
	olsPointMoved: function(startPoint, endPoint, viaPoint, viaId) {
	    if (startPoint) this.olsPanel.setStartAddress(startPoint, this.paramsJS.mappe.SRID);
	    if (endPoint) this.olsPanel.setEndAddress(endPoint, this.paramsJS.mappe.SRID);
	    if (viaPoint) this.olsPanel.moveViaAddress(viaId, viaPoint, this.paramsJS.mappe.SRID);
	},
		
	/**
	 * Method: olsPointSelected
	 * 
	*/
	olsPointSelected: function(posX, posY, type) {	
		var viewPos = this.getViewerPosition(); 
		var coordinate = this.viewer.pluginGetCoordinateFromPixel({x:(posX-viewPos.x),y:(posY-viewPos.y)}); 
		var currPoint = new Point(coordinate.x,coordinate.y);
		
		switch (type) {
			case 'REVERSE':
			    this.olsPanel.reverseGeocode(currPoint, this.paramsJS.mappe.SRID);
				break;
			case 'START':
				this.addStartRoutingMarker(coordinate.x, coordinate.y, this.paramsJS.mappe.SRID);
			    this.olsPanel.setStartAddress(currPoint, this.paramsJS.mappe.SRID);
				break;
			case 'END':
				this.addEndRoutingMarker(coordinate.x, coordinate.y, this.paramsJS.mappe.SRID);
			    this.olsPanel.setEndAddress(currPoint, this.paramsJS.mappe.SRID);
				break;
			case 'VIA':
			    var viaId = this.olsPanel.addViaAddress(currPoint, this.paramsJS.mappe.SRID);
				this.addViaRoutingMarker(viaId, coordinate.x, coordinate.y, this.paramsJS.mappe.SRID);
				break;
		}
	},
	
	queryPanelSetGeomField: function() {
		var box = this.viewer.pluginGetMapExtent();
		var p1 = "" +  box.left + " " + box.top;
		var p2 = "" +  box.left + " " + box.bottom;
		var p3 = "" +  box.right + " " + box.bottom;
		var p4 = "" +  box.right + " " + box.top;
		
		var geom = "POLYGON((" + p1 + "," + p2 + "," + p3 + "," + p4 + "," + p1+ "))";
		this.queryPanel.setGeomFilterField(geom);
	},
	
	
	/**
	 * Method: bindToViewerPanel
	 * 
	 */
	bindToViewerPanel: function() {
		
		if (this.viewer!=null) {
				
			// Sarebbe più corretto gestire il selectRequestStart, ma è poco reattivo perché l'esecuzione della richiesta prende tempo 
			this.on('selectRequestBeforeStart', function(){				
				//this.viewer.pluginOnRequestStart();		
				Ext.each(this.viewer.getEl().query('div'),function(e){Ext.fly(e).addCls('cursorProgress');});
			}, this);
			
			this.on('selectRequestEnd', function(){
				//this.viewer.pluginOnRequestEnd();				
				Ext.each(this.viewer.getEl().query('div'),function(e){Ext.fly(e).removeCls('cursorProgress');});
			}, this);
			
			if (this.TOCPanel!=null) {
				var viewer = this.viewer;
				var api = this;
				//this.viewer.on('scalechange', function(scale) { this.requestVisibleData(scale); }, this.TOCPanel);
				this.viewer.on('scalechange', function(scale) { 
					this.createOrUpdate(scale, undefined, api.viewer.pluginGetObjPos()); 
				}, this.TOCPanel);			
				
				this.viewer.on('onMapMoveEnd', function(scale) { 
					this.createOrUpdate(api.viewer.pluginGetCurrentZoom(), undefined, api.viewer.pluginGetObjPos()); 
				}, this.TOCPanel);			
					
				if (this.queryPanel) {
					this.viewer.on('onMapMoveEnd', this.queryPanelSetGeomField, this);
				}
				
				//loadend
				this.viewer.addListener('onAfterPostInit', function() {
					this.TOCPanel.createOrUpdate(this.viewer.pluginGetCurrentZoom(), false, this.viewer.pluginGetObjPos());
				}, this, { single: true });
													
				//TODO ma quando arriva qua probabilmente afterlayout lo ha già fatto!!!
				//this.viewer.on('afterlayout', function() { api.TOCPanel.showTOC(viewer.pluginGetCurrentZoom()); }, this.TOCPanel, {single:true});
		
				this.TOCPanel.on('layerCheckedChange', this.onLegendaCheckLayerChange, this);
				this.TOCPanel.on('categoryCheckedChange', this.onLegendaCheckCategoryChange, this);
				this.TOCPanel.on('layerOrderChanged', this.onLegendaOrderChange, this);
				this.TOCPanel.on('layerStyleChanged', this.onLegendaStyleChange, this);
				
				this.TOCPanel.on('categoryAdded', this.onLegendaCategoryAdded, this);
				this.TOCPanel.on('layerAdded', this.onLegendaLayerAdded, this);
				
				this.TOCPanel.on('contextMenuAddWMSFromCatalogClick', this.addWMSFromCatalogChoose, this);
				this.TOCPanel.on('contextMenuAddWMSFromWMSWidgetClick', this.addWMSFromWMSWidgetChoose, this);
				
				
			}
						
			this.viewer.on('onAutoIdentify', this.onAutoIdentify, this);
			this.viewer.on('onAutoIdentifyCancel', this.onAutoIdentifyCancel, this);
			
			// Registrazione in viewerPanel
			//this.viewer.on('onMeasureStart', this.onMeasureCallback, this);
			//this.viewer.on('onMeasureStop', this.onMeasureCallback, this);
			//this.viewer.on('onMeasureChanging', this.onMeasureCallback, this);
			//this.viewer.on('onMeasureChanged', this.onMeasureCallback, this);
			//this.viewer.on('onMeasureClear', this.onMeasureCallback, this);
			
			this.viewer.on('onDigitizeEndPoint',         this.onDigitizeEndPoint, this);
			this.viewer.on('onDigitizeEndLine',          this.onDigitizeEndLine, this);
			this.viewer.on('onDigitizeEndPolygon',       this.onDigitizeEndPolygon, this);
			this.viewer.on('onDigitizeEndVertexEditing', this.onDigitizeEndVertexEditing, this);
			this.viewer.on('onDigitizeEndDragDrop',      this.onDigitizeEndDragDrop, this);
			//this.viewer.on('onMappaSelect',              function (point,selectionMode,addToSelected,visualize) {this.onMappaSelect(point,selectionMode,addToSelected,visualize); }, this );
			this.viewer.on('onMappaSelect',              this.onMappaSelect, this );
			this.viewer.on('onPrintMap',                 this.showPrintWindow,  this );
			//this.viewer.on('onCoordinateChange',		 this.showCoordinate, this)
			
			this.viewer.on('onTimeMachineHide', function() {this.buttonsPanel.buttonToggle(TolomeoExt.ToloAPIOpCodes.btnTimeMachine, null, true)},  this );			
			this.viewer.on('popupClicked', this.updateNoteOnMap,  this );
			this.viewer.on('previousNavigationStateAvailable',		function(){this.fireEvent('previousNavigationStateAvailable')}, this);
			this.viewer.on('previousNavigationStateNotAvailable',	function(){this.fireEvent('previousNavigationStateNotAvailable')}, this);
			this.viewer.on('nextNavigationStateAvailable',			function(){this.fireEvent('nextNavigationStateAvailable')}, this);
			this.viewer.on('nextNavigationStateNotAvailable',		function(){this.fireEvent('nextNavigationStateNotAvailable')}, this);
			
			if (this.statusPanel) {
				//id: id+"-statusPanelCoordPnl",
												
				this.statusPanel.add({
					text: '',
					id: 'qgisConnection',
					hidden : true,
	    			iconCls : 'iconConnected2QGis',
					cls : "clearCss",
					listeners: { 								
						click: {
							fn: function() {     	    								
								Ext.MessageBox.show({
					    			title: ToloI18n.getMsg("ToloMapAPIExt.QGisConnection.click.title"),
					                msg: ToloI18n.getMsg("ToloMapAPIExt.QGisConnection.click.msg"),				                
					                width:300,				                
					                animateTarget: 'qgisConnection',
					                iconCls : 'iconConnected2QGis'
					            });																										
							},
							scope: this
			    		}
					},
					tooltip: {text: ToloI18n.getMsg("ToloMapAPIExt.QGisConnection.tootip.text"), title: ToloI18n.getMsg("ToloMapAPIExt.QGisConnection.tootip.title")}					
				});
				
				this.statusPanel.add('-');				
				
				var coordPnl = new Ext.Toolbar.TextItem({ cls: 'x-status-text-panel'});			
				var bFatto=false;
				// Dovuto sovrascrivere il metodo facendo in modo che updateLAyout fosse lanciato una volta solo perchè altrimenti era lentissimo
				coordPnl.setText= function(text) {
			        var me = coordPnl;
			        me.text = text;
			        if (me.rendered) {
			            me.el.update(text);
			            if (!bFatto) {
			            	bFatto=true;
			            	me.updateLayout();
			            }
			        }
			    }
				this.statusPanel.add(coordPnl);
				
				this.viewer.on('onMouseCoordChange', 
						function(coords,units,srid){
							var nDec = (units=='degrees' || units=='dd') ? 4 : 0;
							
							var x = this.addThousandSeparator(coords.x.toFixed(nDec), '.', ',');
							var y = this.addThousandSeparator(coords.y.toFixed(nDec), '.', ',');
							
							var msg = (srid ? srid + '&nbsp;&nbsp;' : '') + "X: " + x+'&nbsp;&nbsp;'+"Y: " + y;
							
							coordPnl.setText(msg);
							} , this);
							//this.statusPanel.find("id",this.id+"-statusPanelCoordPnl")[0].setText("X: " + x+'&nbsp;&nbsp;'+"Y: " + y);} , this);
			}
			
			
		}
	},

	
	/*
	 * addPointCatIdx: (addPointCatIdx) ? addPointCatIdx : "0",
	 							addPointLayIdx: (addPointLayIdx) ? addPointLayIdx : undefined,
	 							bBefore: bBefore
	 */
	
	addWMSFromWMSWidgetChoose: function(addPointCatIdx, addPointLayIdx, bBefore) {
		
		this.wmsExplorerWidgetActivate(addPointCatIdx, addPointLayIdx, bBefore);
		
	},
	
	addWMSFromCatalogChoose: function(addPointCatIdx, addPointLayIdx, bBefore) {
		
		this.cswWidgetActivate(addPointCatIdx, addPointLayIdx, bBefore);
		
	},
	
	addThousandSeparator: function (str, thousandSeparator, decimalSeparator) {
		var sRegExp = new RegExp('(-?[0-9]+)([0-9]{3})'),
		sValue = str + "", // to be sure we are dealing with a string
		arrNum = [];

		if (thousandSeparator === undefined) {thousandSeparator = ","; }
		if (decimalSeparator === undefined) {decimalSeparator = "."; }

		arrNum = sValue.split(/\.|,/);
		// let's be focused first only on the integer part
		sValue = arrNum[0];

		while(sRegExp.test(sValue)) {
		sValue = sValue.replace(sRegExp, '$1' + thousandSeparator + '$2');
		}

		// time to add back the decimal part
		if (arrNum.length > 1) {
		sValue = sValue + decimalSeparator + arrNum[1];
		}
		return sValue;
	},
	
	onLegendaCheckLayerChange: function(layerInfo) {
		
		if (layerInfo.itemType=='layer') {
			//this.attributionsChange();
			// TODO gestita solo mappa 0
			var nMappa = 0;
			
			var layerAggreg = this.paramsJS.updateMapDefinitionLayerCheckState(nMappa, layerInfo);		
			var layAndStyle = this.paramsJS.getLayerAggregLayersAndStylesStrings(nMappa, layerAggreg.nPluginLayer, this.layerStringSeparator,this.viewer.pluginGetCurrentZoom()); 
			this.viewer.pluginRefreshMap(layAndStyle.layers, layAndStyle.stili, this.layerStringSeparator, layerAggreg.nPluginLayer);
			this.viewer.pluginRefreshAttribution(layAndStyle.attribution, layerAggreg.nPluginLayer);	
			if (this.viewer3D) {
				this.viewer3D.refreshMap(layerAggreg.nPluginLayer);	
			}
		}
	},
	
	onLegendaCheckCategoryChange: function(catInfo, tocInfo) {
		// TODO gestita solo mappa 0
		var nMappa = 0;
		
		var layerAggregArray = this.paramsJS.updateMapDefinitionCategoryCheckState(nMappa, tocInfo, catInfo);
		for (var i=0; i<layerAggregArray.length; i++) {
			var layerAggreg = layerAggregArray[i];
			var layAndStyle = this.paramsJS.getLayerAggregLayersAndStylesStrings(nMappa, layerAggreg.nPluginLayer, this.layerStringSeparator, this.viewer.pluginGetCurrentZoom()); 
			this.viewer.pluginRefreshMap(layAndStyle.layers, layAndStyle.stili, this.layerStringSeparator, layerAggreg.nPluginLayer);
			this.viewer.pluginRefreshAttribution(layAndStyle.attribution, layerAggreg.nPluginLayer);
			if (this.viewer3D) {
				this.viewer3D.refreshMap(layerAggreg.nPluginLayer);	
			}
		}
	},

	onLegendaOrderChange: function(tocInfo) {
		
		// Ricrea la mapDefinition a partire dalle info di tocInfo (quindi con il nuovo ordine
		this.viewer.pluginRemoveAllLayers();
		this.paramsJS.createMapDefinition(tocInfo);
		this.viewer.pluginAddAllMaps();
		if (this.viewer3D) {
			this.viewer3D.removeAllLayers();
			this.viewer3D.addAllLayers();	
		}
		
	},
	
	//TODO verificare se serve sempre ed eventualmente eliminare
	onLegendaStyleChange: function(layerInfo, style) {
		
		// TODO gestita solo mappa 0
		var nMappa = 0;
		
		var layAggr = this.paramsJS.updateMapDefinitionLayerStyle(nMappa, layerInfo, style); 		
		var layAndStyle = this.paramsJS.getLayerAggregLayersAndStylesStrings(nMappa, layAggr.nPluginLayer, this.layerStringSeparator,this.viewer.pluginGetCurrentZoom()); 
		this.viewer.pluginRefreshMap(layAndStyle.layers, layAndStyle.stili, this.layerStringSeparator, layAggr.nPluginLayer);	
		if (this.viewer3D) {
			this.viewer3D.refreshMap(layerAggreg.nPluginLayer);	
		}

	},
	
	/**
	 * @method attributionsChange Aggiorna tutte le attribuzioni. Attualmente gestita solo mappa numero 0  
	 * 
	 * @param {Object} layerInfo Informazioni del layer, contenenti la nuova attribuzione
	 */
	attributionsChange: function() {
		
		// TODO gestita solo mappa 0
		var nMappa = 0;
		this.paramsJS.updateMapDefinitionAttributions(nMappa, this.TOCPanel.tocInfo);
		
		for (var i=0; i<this.paramsJS.mapDefinitions[nMappa].getLayerAggregationCount(); i++) {
			var layAggr = this.paramsJS.mapDefinitions[nMappa].getLayerAggregation(i);
			var layAndStyle = this.paramsJS.getLayerAggregLayersAndStylesStrings(nMappa, layAggr.nPluginLayer, this.layerStringSeparator,this.viewer.pluginGetCurrentZoom()); 
			this.viewer.pluginRefreshAttribution(layAndStyle.attribution, layAggr.nPluginLayer);	
			if (this.viewer3D) {
				this.viewer3D.refreshMap(layerAggreg.nPluginLayer);	
			}
		}

	},
	
	onLegendaCategoryAdded: function(tocInfo, catInfo) {
		
		// TODO Si può ottimizzare? Così ricalcolo tutto...
		// Se si assume che venga inserita una categoria vuota basterebbe (forse) reindicizzare le layerAggregations
		this.viewer.pluginRemoveAllLayers();
		this.paramsJS.createMapDefinition(tocInfo);
		this.viewer.pluginAddAllMaps();

		if (this.viewer3D) {
			this.viewer3D.removeAllLayers();
			this.viewer3D.addAllLayers();	
		}
		
	},
			
	onLegendaLayerAdded: function(tocInfo, paramsLayInfo, layTocInfo, serverInfo) {
		//TODO ALE
		this.buttonsPanel.a(this.paramsJS.azioniEventi.eventiLayerList);
		this.togglePermittedOperations();
		
		// TODO Si può ottimizzare? Così ricalcolo tutto... tenere presente che il layer aggiunto non è presente negli attuali raggruppamenti
		this.viewer.pluginRemoveAllLayers();
		this.paramsJS.createMapDefinition(tocInfo);
		this.viewer.pluginAddAllMaps();
		if (this.viewer3D) {
			this.viewer3D.removeAllLayers();
			this.viewer3D.addAllLayers();	
		}
		
	},
	
	bindToStylePanel: function() {
		
		if (this.stylePanel) {
			//styleApply: { fn: this.setLayerStyle, scope: this }
			if (this.TOCPanel) {
				this.stylePanel.on('styleApply', this.TOCPanel.setLayerStyle, this.TOCPanel); 
			}
		}
	},
	
	 /**
	    * Method: bindToButtonsPanel
	    * 
	    */
	bindToButtonsPanel: function() {
		// Bind con eventi buttonPanel (se presente
		if (this.buttonsPanel) {
			this.buttonsPanel.on('onTimeMachinePressFn', function() { this.viewer.pluginShowTimeMachine(true); }, this);
			this.buttonsPanel.on('onTimeMachineReleaseFn', function() { this.viewer.pluginShowTimeMachine(false); }, this);
			
			
			this.buttonsPanel.on('onPanPressFn', this.viewer.pluginToolSelectPan, this.viewer);
			this.buttonsPanel.on('onPanReleaseFn', this.viewer.pluginToolSelectPanStop, this.viewer);
			
			this.buttonsPanel.on('onCustomButtonPressFn',   function (btn) { this.onCustomButtonPress(btn)  }, this);
			this.buttonsPanel.on('onCustomButtonReleaseFn', function (btn) { this.onCustomButtonRelease(btn)}, this);
			
			this.buttonsPanel.on('onNuovoPressFn',   function (button) {
				switch(button.newType){
					case 0:
						this.onDigitizeStart(this.digitizeOperationInsert);
					break;
					case 1:
						this.onDigitizeByCADStart(this.digitizeOperationInsert);
					break;
				} 
			}, this );
			this.buttonsPanel.on('onNuovoReleaseFn', function (button) {
				switch(button.newType){
					case 0: 
						this.onDigitizeStop(this.digitizeOperationInsert);
					break;
					case 1:
						this.onDigitizeByCADStop(this.digitizeOperationInsert);
					break;		
				}			  
			}, this );
			
			this.buttonsPanel.on('onNuovoDaLayerPressFn', this.nuovoDaLayerStart, this );
			this.buttonsPanel.on('onNuovoDaLayerReleaseFn', this.nuovoDaLayerStop, this );
			
			this.buttonsPanel.on('onNuovoDaImportPressFn', this.nuovoDaImportStart, this );
			this.buttonsPanel.on('onNuovoDaImportReleaseFn', this.nuovoDaImportStop, this );
			
			this.buttonsPanel.on('onPanNordPressFn',  function () { this.panNord(null);  }, this);
			this.buttonsPanel.on('onPanSudPressFn',   function () { this.panSud(null);   }, this);
			this.buttonsPanel.on('onPanOvestPressFn', function () { this.panOvest(null); }, this);
			this.buttonsPanel.on('onPanEstPressFn',   function () { this.panEst(null);   }, this);		

			this.buttonsPanel.on('onHistoryNextPressFn',   this.historyNext, this);		
			this.buttonsPanel.on('onHistoryPrevPressFn',   this.historyPrev, this);	
			
			this.buttonsPanel.on('onZoomInPressFn',  this.viewer.pluginToolSelectZoomIn,  this.viewer);
			this.buttonsPanel.on('onZoomOutPressFn', this.viewer.pluginToolSelectZoomOut, this.viewer);
			this.buttonsPanel.on('onZoomBoxPressFn', this.viewer.pluginToolSelectZoomBoxActivate, this.viewer);
			this.buttonsPanel.on('onZoomBoxReleaseFn', this.viewer.pluginToolSelectZoomBoxDeactivate, this.viewer);			
			this.buttonsPanel.on('onZoomAllPressFn', this.viewer.pluginToolSelectZoomAll, this.viewer);
		    
		    // TODO DA TRASFERIRE su viewer? Non sono coinvolti metodi dell'API
			this.buttonsPanel.on('onMeasureActivate',   function (type) { this.viewer.pluginMeasureToolSelect(type); }, this);
			this.buttonsPanel.on('onMeasureDeactivate', this.viewer.pluginMeasureStop, this.viewer);
			this.buttonsPanel.on('onMeasureTypeChange', function (type) { this.viewer.pluginMeasureStop(); this.viewer.pluginMeasureToolSelect(type); }, this );
		    
			this.buttonsPanel.on('onPrintPressFn', this.viewer.pluginToolSelectPrint, this.viewer);
		    
		    //TODO
			if (this.TOCPanel!=null)   this.buttonsPanel.on('onLegendPressFn',   function() { this.TOCPanel.showTOC(this.viewer.pluginGetCurrentZoom()); }, this);
			if (this.TOCPanel!=null)   this.buttonsPanel.on('onLegendReleaseFn', this.TOCPanel.hideTOC, this.TOCPanel);
			if (this.queryPanel!=null) this.buttonsPanel.on('onQueryPressFn',    this.queryPanel.showQuery, this.queryPanel);
			if (this.queryPanel!=null) this.buttonsPanel.on('onQueryReleaseFn',  this.// TODO STILI
					queryPanel.hideQuery, this.queryPanel);
		    
			this.buttonsPanel.on('onSelectPressFn',   this.viewer.pluginToolSelectSelect,     this.viewer);
		    this.buttonsPanel.on('onSelectReleaseFn', this.viewer.pluginToolSelectSelectStop, this.viewer);
			this.buttonsPanel.on('onIdentifyPressFn', this.onIdentify,                        this);
		    //this.buttonsPanel.on('onIdentifyReleaseFn', this);
		    
			this.buttonsPanel.on('onDeletePressFn',     this.onDelete,     this);
			this.buttonsPanel.on('onUpdateAlfaPressFn', this.onUpdateAlfa, this);
			this.buttonsPanel.on('onAddPressFn',        function () { this.onDigitizeStart(this.digitizeOperationAdd); }, this);
		    
			this.buttonsPanel.on('onAddReleaseFn',        function () { this.onDigitizeStop(this.digitizeOperationAdd);         }, this);
			this.buttonsPanel.on('onSubtractPressFn',     function () { this.onDigitizeStart(this.digitizeOperationSubtract);   }, this);
			this.buttonsPanel.on('onSubtractReleaseFn',   function () { this.onDigitizeStop(this.digitizeOperationSubtract);    }, this);
			this.buttonsPanel.on('onAddSubPressFn',       function () { this.onDigitizeStart(this.digitizeOperationAddSub);     }, this);
			this.buttonsPanel.on('onAddSubReleaseFn',     function () { this.onDigitizeStop(this.digitizeOperationAddSub);      }, this);
			this.buttonsPanel.on('onVertexEditPressFn',   function () { this.onDigitizeStart(this.digitizeOperationVertexEdit); }, this);
			this.buttonsPanel.on('onVertexEditReleaseFn', function () { this.onDigitizeStop(this.digitizeOperationVertexEdit);  }, this);
			this.buttonsPanel.on('onDragDropPressFn',     function () { this.onDigitizeStart(this.digitizeOperationDragDrop);   }, this);
		    
			this.buttonsPanel.on('onDragDropReleaseFn',       function () { this.onDigitizeStop(this.digitizeOperationDragDrop); } , this);
			this.buttonsPanel.on('onAnnullaSelezioniPressFn', this.onAnnullaSelezioni, this);
		    
			this.buttonsPanel.on('onTemporalFilterApply', this.temporalFilterApply, this);
			
			this.buttonsPanel.on('onAutoIdentifyPressFn',   function () {this.autoIdentifyEnable(true); }, this);
			this.buttonsPanel.on('onAutoIdentifyReleaseFn', function () {this.autoIdentifyEnable(false); }, this);			
			this.buttonsPanel.on('onSelectLayer',           function (codTPN) { this.setCurrentSelectLayer(codTPN); }, this);
			
			this.buttonsPanel.on('onSnapPressFn',   function () { this.viewer.pluginSnapActivate(this.currentSelectedLayer); }, this);
			this.buttonsPanel.on('onSnapReleaseFn', function () { this.viewer.pluginSnapClear(); }, this);
			this.buttonsPanel.on('onCswPressFn', function () { this.cswWidgetActivate(); }, this);
			this.buttonsPanel.on('onCswReleaseFn', function () { this.cswWidgetDeactivate(); }, this);
			this.buttonsPanel.on('onWMSPressFn', function () { this.wmsExplorerWidgetActivate(); }, this);
			this.buttonsPanel.on('onWMSReleaseFn', function () { this.wmsExplorerWidgetDeactivate(); }, this);
			
			this.buttonsPanel.on('on3DPressFn', function () { this.viewer3DWidgetActivate(); }, this);
			this.buttonsPanel.on('on3DReleaseFn', function () { this.viewer3DWidgetDeactivate(); }, this);
			
			this.buttonsPanel.on('showPermalinkClicked', function () { this.showPermalink(); }, this);
			this.buttonsPanel.on('exportForQgisClicked', function (catIdx, layIdx, version) { this.exportForQgis(catIdx, layIdx, version); }, this);
			this.buttonsPanel.on('showTolomeoInfoClicked', function () { this.tolomeoInfoWin.show();}, this);
			this.buttonsPanel.on('showCustomInfoClicked', function (args) { this.showCustomInfo(args);}, this);
			this.buttonsPanel.on('regeneratePageClicked', function () { this.regeneratePage();}, this);
			this.buttonsPanel.on('showGuideClicked', function (url) { this.showGuide(url);}, this);
			this.buttonsPanel.on('showFaqClicked', function (url) { this.showFaq(url);}, this);
			this.buttonsPanel.on('mailToAdministratorClicked', function (to,subject) { this.mailToAdmin(to,subject);}, this);
			
			this.buttonsPanel.on('showWithOSMClicked', function () { this.apriMappaOSM(); }, this);
			this.buttonsPanel.on('showWithGoogleSatelliteClassicClicked', function () { this.apriMappaGoogle('k', true); }, this);
			this.buttonsPanel.on('showWithGoogleMapClassicClicked', function () { this.apriMappaGoogle('h', true); }, this);
			this.buttonsPanel.on('showWithGoogleSatelliteClicked', function () { this.apriMappaGoogle('k', false); }, this);
			this.buttonsPanel.on('showWithGoogleMapClicked', function () { this.apriMappaGoogle('m', false); }, this);
			this.buttonsPanel.on('showWithBingObClicked', function () { this.apriMappaBing('b', 0); }, this);
			this.buttonsPanel.on('showWithBingSatelliteClicked', function () { this.apriMappaBing('h', 0); }, this);
			this.buttonsPanel.on('showWithBingMapClicked', function () { this.apriMappaBing('r', 0); }, this);
			this.buttonsPanel.on('showWithHereSatelliteClicked', function () { this.apriMappaHere('satellite'); }, this);
			this.buttonsPanel.on('showWithHereMapClicked', function () { this.apriMappaHere('normal'); }, this);
			
			this.buttonsPanel.on('languageChange', this.languageChange, this);
			
			this.buttonsPanel.bindToAPI(this);
		}
	},
	
  /**
    * Method: bindToContextMenu
    * Crea il contextMenu se non esiste, lo lega al viewer e ne gestisce gli eventi
    * 
    */
	bindToContextMenu: function() {
		// Bind con eventi contextMenu 
		if (!this.contextMenu) {
			this.contextMenu = new TolomeoExt.ToloContextMenu({projectionCrs:this.projectionCrs,allowOtherMenus: false,paramsJS: this.paramsJS});
			this.fireEvent("afterContextMenuCreate", this.contextMenu);
		}
		if (this.viewer.map) {
			this._registerContextMenu();		
		} else {
			this.viewer.on('onAfterPostInit', 
				function(ev) {
					this._registerContextMenu();
					/*
					this.contextMenu.setCrsSelected(this.getProjectionCode());
					this.viewer.getEl().on('contextmenu', // TODO STILI
							
						function(e) {
							e.preventDefault(); 
							this.contextMenu.showAt(e.getXY());						
						}, this);*/
					}
				, this,{single: true});
		}
			
		this.contextMenu.on('onGotoLocClickFn', this.gotoLocationEnable, this);
		this.contextMenu.on('onReleaseLocClickFn', this.releaseLocationEnable, this);
		this.contextMenu.on('onReleaseStreetviewClickFn', this.releaseStreetviewEnable, this);
		this.contextMenu.on('onNotaClickFn', this.insertNoteOnMap, this);
		
		if (this.olsPanel!=null) {
			this.contextMenu.on('onOlsMethod', function(method) {
				this.olsPanel.setMethod(method);
			}, this);
			this.contextMenu.on('onOlsReverseGeocoding', function(posX, posY) {	
				this.olsPointSelected(posX, posY, 'REVERSE');
			}, this);
			this.contextMenu.on('onOlsStartPoint', function(posX, posY) {	
				this.olsPointSelected(posX, posY, 'START');
			}, this);
			this.contextMenu.on('onOlsViaPoint', function(posX, posY) {	
				this.olsPointSelected(posX, posY, 'VIA');
			}, this);
			this.contextMenu.on('onOlsEndPoint', function(posX, posY) {	
				this.olsPointSelected(posX, posY, 'END');
			}, this);
			this.contextMenu.on('onOlsReset', function() {
				this.olsPanel.reset();
				this.clearRouting();
				this.viewer.pluginClearStartRoutingMarker();
				this.viewer.pluginClearEndRoutingMarker();
				this.viewer.pluginClearViaRoutingMarkers();	
				this.viewer.pluginRoutingDeactivate();
			}, this);
		}
		
	},
	
	
	_registerContextMenu: function() {
		this.contextMenu.setCrsSelected(this.getProjectionCode());
		this.viewer.getEl().on('contextmenu', // TODO STILI				
			function(e) {
				e.preventDefault(); 
				this.contextMenu.showAt(e.getXY());						
			}, this);
	},

	bindToStatusPanel: function(){
		if(this.statusPanel){
		
			this.setStatusMode = function(functionMode,functionType){
				if(!functionMode) return;
				this.statusPanel.defaultText=ToloI18n.getMsg("ToloMapAPIExt.statusPanel.defaultText", {FUNCTIONMODE: functionMode, FUNCTIONTYPE: (functionType ? " : " + functionType : "")} );
				this.statusPanel.clearStatus({useDefaults:true});
			}
			
			this.on('selectRequestBeforeStart',function(){
				this.statusPanel.showBusy(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.showBusy"));
				
			},this);
			
			this.on('selectRequestEnd',function(esito){				
				this.statusPanel.setStatus({
				    text: esito.ok?ToloI18n.getMsg("ToloMapAPIExt.statusPanel.requestEnd.text", {NRESULT: esito.nResults}):ToloI18n.getMsg("ToloMapAPIExt.statusPanel.requestEnd.Errore.text"),
				    iconCls: esito.nResults==0?'x-status-error':'x-status-valid',
				    clear: true // auto-clear after a set interval
				});
			},this);
			
			if(this.statusPanel.rendered){
				this.setStatusMode("panoramica");
			}else{
				this.statusPanel.on('afterrender',function(){this.setStatusMode("panoramica");},this)
			}

			
			
			if(this.buttonsPanel){
				this.buttonsPanel.on('onPanPressFn',        function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.panoramica"));},this);
				this.buttonsPanel.on('onZoomBoxPressFn',    function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.panoramica"),
																				ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.panoramica.zoombox"));} , this);
				this.buttonsPanel.on('onSelectPressFn',     function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.selezione"));} , this);
				this.buttonsPanel.on('onNuovoPressFn',      function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.nuovo"));} , this);
				this.buttonsPanel.on('onNuovoDaLayerPressFn',      function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.nuovoDaLayer"));} , this);
				this.buttonsPanel.on('onNuovoDaImportPressFn',      function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.nuovoDaImport"));} , this);
				this.buttonsPanel.on('onUpdateAlfaPressFn', function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.updateAlpha"));} , this);
				this.buttonsPanel.on('onAddPressFn',        function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.unione"));} , this);
				this.buttonsPanel.on('onSubtractPressFn',   function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.sottrazione"));} , this);
				this.buttonsPanel.on('onAddSubPressFn',     function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.copertura"));} , this);
				this.buttonsPanel.on('onVertexEditPressFn', function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.vertexEd"));} , this);
				this.buttonsPanel.on('onDragDropPressFn',   function(){this.setStatusMode(ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing"),
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.editing.dragdrop"));} , this);
				this.buttonsPanel.on('onMeasureActivate',   function(measureType){
					var mt = "";
					switch (measureType){
						case 0: mt = ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.misura.misurapol");
							break;
						case 1: mt = ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.misura.misuracer");
							break;
						default: mt = ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.misura.misuralin");
					}
					
					this.setStatusMode(
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.misura"), mt);}, this);
				this.buttonsPanel.on('onMeasureTypeChange', function(measureType){
					var mt = "";
					switch (measureType){
						case 0: mt = ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.misura.misurapol");
							break;
						case 1: mt = ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.misura.misuracer");
							break;
						default: mt = ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.misura.misuralin");
					}

					this.setStatusMode(
						ToloI18n.getMsg("ToloMapAPIExt.statusPanel.mode.misura"),mt);}, this);
				
			}
		}
	},
	
	bindToQueryBuilderPanel: function(){
		var mapApiExt = this;
		var tolomeoViewer = mapApiExt.viewer;
		if (this.queryBuilderPanel) {
			tolomeoViewer.on("onAfterPreInit", function(){
				var qbEventManager = mapApiExt.queryBuilderPanel.getQbEventManager();
				qbEventManager.setMap(tolomeoViewer.map);
				if(mapApiExt.projectionCrs[mapApiExt.getProjectionCode()]){
					mapApiExt.queryBuilderPanel.spatialSelector.setDecimalPrecision(mapApiExt.projectionCrs[mapApiExt.getProjectionCode()].precision);
				}
			});											
		}
		
	},

	bindToCodeLessPanel: function(){
		var mapApiExt = this;
		var tolomeoViewer = mapApiExt.viewer;
		tolomeoViewer.on("onAfterPreInit", function(){
			if(mapApiExt.codeLessPanel){
				mapApiExt.codeLessPanel.setMapApiExt(mapApiExt);
			}
		})	
	},
	
	bindToViewCodeLessPanel: function(){
		var mapApiExt = this;
		var tolomeoViewer = mapApiExt.viewer;
		tolomeoViewer.on("onAfterPreInit", function(){
			if(mapApiExt.viewCodeLessPanel){
				mapApiExt.viewCodeLessPanel.setMapApiExt(mapApiExt);
			}
		})	
	},
	
	viewer3DWidgetActivate: function() {
		if (this.viewer3DWidget == null) {
		
			var me = this;
			
			this.lazyLoadScript('cesium',
					function() {
						// // {left: bounds.left, bottom: bounds.bottom, right: bounds.right, top: bounds.top} 
						var extent = me.viewer.pluginGetMapExtent();
						var ul = new Point(extent.left, extent.top);
						var br = new Point(extent.right, extent.bottom);  
					    ul.transform(me.viewer.pluginGetProjectionCode(),"EPSG:4326");    
					    br.transform(me.viewer.pluginGetProjectionCode(),"EPSG:4326");
					    this.viewer3D =	new TolomeoExt.ToloCesiumPanelExt({
					    		paramsJS: this.paramsJS,
					    		TOLOMEOServer: this.TOLOMEOServer,
					    		TOLOMEOStaticRoot: this.TOLOMEOStaticRoot,
					    		TOLOMEOContext: this.TOLOMEOContext,
					    		startExtentWest: ul.x,
						  		startExtentEast: br.x,
						  		startExtentNorth: ul.y,
						  		startExtentSouth: br.y,
						  		listeners: {
										'closePressed': function() {
												me.viewer3DWidgetActivate();	
										}
									}
						  	});  
							
					    this.viewer3DWidget = Ext.create('Ext.Window', {
								width: 500,
								height: 500,
								layout: 'fit',
								title: ToloI18n.getMsg("ToloMapAPIExt.viewer3DWidget.title"),
								constrain: true,
								maximizable: true,
								items: [ this.viewer3D  ],
								closeAction: 'destroy',
								listeners: {'close' : function() {
										me.viewer3DWidget = null;
										me.viewer3D = null;
										me.buttonsPanel.buttonToggle(TolomeoExt.ToloAPIOpCodes.btn3D, null, true);
										
									}
								}
						});	
				
					    this.viewer3DWidget.show();
				
					},
					function(){Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.viewer3DWidget.alert.title"), ToloI18n.getMsg("ToloMapAPIExt.viewer3DWidget.alert.msg"),
								function(){this.buttonsPanel.buttonToggle(TolomeoExt.ToloAPIOpCodes.btn3D, null, true);}, this);},
					this
				);
		} else {
			this.viewer3DWidget.show();
		}
		
		
	},
	
	viewer3DWidgetDeactivate: function() {
		if (this.viewer3DWidget != null) {
			this.viewer3DWidget.close();
			this.viewer3DWidget = null;
			this.viewer3D = null;
			this.buttonsPanel.buttonToggle(TolomeoExt.ToloAPIOpCodes.btn3D, null, true);
		}
	},
	
	setViewer3D: function(viewer3D) {
		this.viewer3D = viewer3D;
	},

	/**
	 * Method: temporalFilterApply
	 * Applica il filtro temporale
	 * 
	 */
	temporalFilterApply: function(dtInizio, dtFine){
		this.temporalFilterDtInizio = (dtInizio != null && dtInizio!="") ? Ext.Date.format(dtInizio,"d/m/Y") : "01/01/0001";
		this.temporalFilterDtFine   = (dtFine   != null && dtFine!="") ? Ext.Date.format(dtFine,"d/m/Y") : "31/12/2099";
		this.applyCustomQuery();
	},
	
	/**
	 * Method: zoomIn
	 * Esegue lo zoom avanti.
	 * 
	 */
	zoomIn: function(){
		this.viewer.pluginToolSelectZoomIn();		
	},
	
	/**
	 * Method: zoomOut
	 * Esegue lo zoom indietro.
	 * 
	 */
	zoomOut: function(){
		this.viewer.pluginToolSelectZoomOut();
	},
	
	/**
	 * Method: zoomBox
	 * Esegue lo zoom box.
	 * 
	 */
	zoomBox: function(){
		this.viewer.pluginToolSelectZoomBox();
	},

	/**
	 * Method: pan
	 * Esegue il pan.
	 * 
	 * Parameters:
	 * direction - {} direzione di spostamento.
	 * slideFactorPan - {} tolleranza di spostamento
	 */
	pan: function(direction, slideFactorPan){
		this.viewer.pluginPan(direction,slideFactorPan);
	},

	/**
	 * Method: panNord
	 * Esegue il pan verso nord.
	 * 
	 * Parameters:
	 * slideFactor - {} tolleranza di spostamento
	 */
	panNord: function(slideFactorPan){
		this.pan("N",slideFactorPan);
	},

	/**
	 * Method: panSud
	 * Esegue il pan verso sud.
	 * 
	 * Parameters:
	 * slideFactor - {} tolleranza di spostamento
	 */
	panSud: function(slideFactorPan){
		this.pan("S",slideFactorPan);
	},

	/**
	 * Method: panOvest
	 * Esegue il pan verso ovest.
	 * 
	 * Parameters:
	 * slideFactor - {} tolleranza di spostamento
	 */
	panOvest: function(slideFactorPan){
		this.pan("O",slideFactorPan);
	},

	/**
	 * Method: panEst
	 * Esegue il pan verso est.
	 * 
	 * Parameters:
	 * slideFactor - {} tolleranza di spostamento
	 */
	panEst: function(slideFactorPan){
		this.pan("E",slideFactorPan);
	},

	/**
	 * @method historyNext
	 * Sposta alla visualizzazione successiva.
	 * 
	 */
	historyNext: function(){
		if (this.viewer) {
			this.viewer.pluginHistoryNext();
		}
	},

	/**
	 * @method historyPrev
	 * Sposta alla visualizzazione successiva.
	 * 
	 */
	historyPrev: function(){
		if (this.viewer) {
			this.viewer.pluginHistoryPrev();
		}
	},
	
	showTimeMachine: function(show) {
		if (this.viewer) this.viewer.pluginShowTimeMachine(show);
	},
	
	/**
	 * Method: showPrintWindow
	 * Crea una wizard di stampa su una finestra. Nel primo passo imposto la stampa nel secondo la genero.
	 *
	 * Parameters:
	 * url - {String} url.
	 */
	showPrintWindow: function(url) {
		
		var server        = this.TOLOMEOServer;
		var context       = this.TOLOMEOContext;
		var urlMappa      = url;
		var scala         = this.viewer.pluginGetCurrentZoom();
		var unita         = this.viewer.pluginGetUnits();
		var mapx          = this.viewer.pluginGetCurrentX();
		var mapy          = this.viewer.pluginGetCurrentY();
		var mapext        = this.viewer.pluginGetMapExtent();
		var mappaTypeCode = this.paramsJS.mappe.mappaList[0].typeCode; //TODO Funziona solo con mappe con unico strato
		var me =  this;
		
		// Definisce formati di stamapa
		var printFormats = [];
		var n = 3;
		var maxPrintFormat = this.paramsJS.mappe.maxPrintFormat;
		if (maxPrintFormat) {
			n = maxPrintFormat.substring(1,2);	
		} 
		for (var i = 4; i >= n; i--) {
			printFormats.push({
		                checked: (i==4 ? true: false),
		                fieldLabel: '',
		                boxLabel: 'A'+i,
		                name: 'formato',
		                inputValue: 'a'+i
		            });
		}
		
		var comboLegenda = this.geoOpField = Ext.create('Ext.form.field.ComboBox', {
	    	name: 'legendType',
            value: 'separate-A4-1col',
            anchor: '99%',
            fieldLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.comboLegenda.fieldLabel"),            
            labelSeparator: ': ',
            padding: '10 0 10 0',
            mode: 'local',
            triggerAction: 'all',
            forceSelection: true,
            allowBlank: false,
            editable: false,
            lazyInit: false,
            disabled:true,
            listConfig: {
            	getInnerTpl: function() {
        			return '<div data-qtip="{suggerimento}">{descrizione}</div>'; 
            		}
        	},		            
            displayField: 'descrizione',
            valueField: 'valore',
            store: Ext.create('Ext.data.ArrayStore', {
		        //id: 0,			        
		        fields: ['id', 'valore', 'descrizione', 'suggerimento'],    //suggerimento
			    data: [			    	
			    	[1, 'embed', ToloI18n.getMsg("ToloMapAPIExt.printWindow.comboLegenda.sumappa.descrizione"), ToloI18n.getMsg("ToloMapAPIExt.printWindow.comboLegenda.sumappa.suggerimento")],
			    	[2, 'separate-A4-1col', ToloI18n.getMsg("ToloMapAPIExt.printWindow.comboLegenda.unacol.descrizione"), ToloI18n.getMsg("ToloMapAPIExt.printWindow.comboLegenda.unacol.suggerimento")],
			    	[3, 'separate-A4-2col', ToloI18n.getMsg("ToloMapAPIExt.printWindow.comboLegenda.duecol.descrizione"), ToloI18n.getMsg("ToloMapAPIExt.printWindow.comboLegenda.duecol.suggerimento")]			    	
			    ]
		    })
	    });
		
		var parametri = [{
			columnWidth: '1',
			labelWidth: 60,
			xtype: 'container',				
	        items: {
	            xtype: 'fieldset',
	            title: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.title"),
	            autoHeight: true,
	            items: [{
	            	xtype: 'numberfield',
	                fieldLabel: 'Scala 1',
		            name: 'scala',
		            value: Math.round(scala),
		            allowBlank: false,
		            allowDecimals: false,
		            allowNegative: false
		            /*,
		            minValue: 200,
		            maxValue: 300000
		            */
	            },{
	            	xtype: 'textfield',
			    	fieldLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.titolo"),
			    	anchor: '99%',
			    	name: 'titolo',
			    	value: this.titoloMappa,
			    	allowBlank: false,
			    	maxLength: 100
	            },{
	            	xtype: 'textfield',
			    	fieldLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.sottotitolo"),
			    	anchor: '99%',
			    	name: 'sottotitolo',
			    	value: this.sottotitoloMappa,			    	
			    	maxLength: 500
	            },{
			    	xtype: 'htmleditor',
			    	fieldLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.descrizione"),
			    	height: 100,
			    	anchor: '99%',
			    	name: 'descrizione',
			    	value: this.descrizioneMappa,
			    	defaultFont: 'Arial',
			    	enableAlignments: false,
			    	enableFont: false,
			    	enableLinks: false,
			    	enableSourceEdit: false
				},{
		            xtype: 'checkboxgroup',
		            anchor: '99%',
		            fieldLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.fldIncludi"),
		            items: [{
                        xtype: 'checkbox',
                        boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.fldIncludi.url"),
                        name: 'stampaReferer',
                        checked: false
                    },{
                        xtype: 'checkbox',
                        boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.fldIncludi.dataora"),
                        name: 'aggDataOra'
		            },{
                        xtype: 'checkbox',
                        boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.fldIncludi.perma"),
                        name: 'printPermalink',
                        checked: false
		            },{
                        xtype: 'checkbox',
                        boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetPersonalizza.fldIncludi.legenda"),
                        name: 'printLegend',
                        checked: false,
                        listeners: {
					        change: {            
					            fn: function(e,newVal,oldVal){ comboLegenda.setDisabled(!e.checked) }
					        }
    					}
		            }]
	            },comboLegenda]
			}
		},{
			columnWidth: '.3',
			xtype: 'container',				
	        items: {
	            xtype: 'fieldset',
	            title: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetOrien"),
	            height: 100,
	            labelWidth: 10,
	            defaultType: 'radio',
	            items: [{
	                checked: true,
	                fieldLabel: '',
	                boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetOrien.V"),
	                name: 'orientamento',
	                inputValue: 'v'
	            },{
	                fieldLabel: '',
	                labelSeparator: '',
	                boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetOrien.O"),
	                name: 'orientamento',
	                inputValue: 'o'
	            }]
			}
		},{
			bodyStyle: 'padding-left:5px;',
			columnWidth: '.3',
			xtype: 'container',	
	        items: {
	            xtype: 'fieldset',
	            title: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetFormato"),
	            height: 100,
	            labelWidth: 10,
	            defaultType: 'radio',	            
	            items: printFormats
	            /*[{
	                checked: true,
	                fieldLabel: '',
	                boxLabel: 'A4',
	                name: 'formato',
	                inputValue: 'a4'
	            },{
	                fieldLabel: '',
	                labelSeparator: '',
	                boxLabel: 'A3',
	                name: 'formato',
	                inputValue: 'a3'
	        	},{
	                fieldLabel: '',
	                labelSeparator: '',
	                boxLabel: 'A2',
	                name: 'formato',
	                inputValue: 'a2'
	        	}]*/
			}
		},{
			bodyStyle: 'padding-left:5px;',
			columnWidth: '.4',
			xtype: 'container',	
	        items: {
	        	xtype: 'fieldset',
	            title: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetQual"),
	            //autoHeight: true,
	            //fieldLabel: 'Risoluzione',
		        labelWidth: 60,
	            height: 100,
	            items: [{
		            xtype: 'combo',
		            //width: 150,
		            anchor: '-10',
		            labelSeparator: ':\n',
		            mode: 'local',
		            triggerAction: 'all',
		            forceSelection: true,
		            editable: false,
		            lazyInit: false,
		            value: '96',
		            listConfig: {
		            	getInnerTpl: function() {
	            			return '<div data-qtip="{suggerimento}">{descrizione}</div>'; 
		            		}
	            	},
		            fieldLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetQual.label"),
		            name: 'dpiStampa',
		            hiddenName: 'dpiStampa',
		            displayField: 'descrizione',
		            valueField: 'valore',
		            store: Ext.create('Ext.data.ArrayStore', {
				        //id: 0,			        
				        fields: ['id', 'valore', 'descrizione', 'suggerimento'],    //suggerimento
					    data: [
					    	[1, '96' , ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetQual.dpi96.desc"), ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetQual.dpi96.sugg")],
					    	[2, '150', ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetQual.dpi150.desc"), ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetQual.dpi150.sugg")],
					    	[3, '300', ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetQual.dpi300.desc"), ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetQual.dpi300.sugg")]
					    ]
				    })
	            }]
            }
		},{
			columnWidth: '1',
			xtype: 'container',	
			items: {
	            xtype: 'fieldset',
	            title: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetEsp"),
	            autoHeight: true,
	            items: {
		        	xtype: 'radiogroup',
		            columns: 2,
		            items: [
		                {boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetEsp.pdf"),  name: 'esportazione', inputValue: 'pdf', checked: true/*, 
		                listeners: {
					        change: {            
					            fn: function(e,newVal,oldVal){ comboLegenda.setDisabled(!e.checked) }
					        }
    					}*/},
		                {boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetEsp.imm"),   name: 'esportazione', inputValue: 'png'},
		                {boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetEsp.docx"), name: 'esportazione', inputValue: 'docx'},
		                {boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetEsp.rtf"),                name: 'esportazione', inputValue: 'rtf'},
		                {boxLabel: ToloI18n.getMsg("ToloMapAPIExt.printWindow.fldsetEsp.odt"),                name: 'esportazione', inputValue: 'odt'}
		            ]
	            }
			}
	    },
	    	{ xtype: 'hidden', name: 'iehack',            value: String.fromCharCode(153)},
	    	{ xtype: 'hidden', name: '_charset_',         value: ''},
			//{ xtype: 'hidden', name: 'mappaTypeCode',     value: mappaTypeCode},
	    	{ xtype: 'hidden', name: 'mapx',              value: mapx},
	    	{ xtype: 'hidden', name: 'mapy',              value: mapy},
	    	{ xtype: 'hidden', name: 'bbox',            value: (mapext.left + "," + mapext.bottom + "," + mapext.right + "," + mapext.top)},
	    	{ xtype: 'hidden', name: 'unita',             value: unita},
			//{ xtype: 'hidden', name: 'urlMappa',          value: escape(unescape(urlMappa))},
			{ xtype: 'hidden', name: 'urlLogo',           value: this.urlLogo},
			{ xtype: 'hidden', name: 'urlLogoSecondario', value: this.urlLogoSecondario},	
			{ xtype: 'hidden', name: 'projectionCode',    value: this.getProjectionCode()},
			{ xtype: 'hidden', name: 'permalinkHref',     value: ''/*, id : 'permalinkHref'*/}
		];
		
		for (var i=0; i < urlMappa.length; i++ ) {
			
			parametri.push({ xtype: 'hidden', 
							 name: 'urlMappa', 
							 value: escape(unescape(urlMappa[i].url))});
			
			parametri.push({ xtype: 'hidden', 
							name: 'mappaTypeCode', 
							value: urlMappa[i].typeCode});
			
			// TODO gestita solo mappa 0
			var nMappa = 0;
			var lag = this.paramsJS.mapDefinitions[nMappa].whichLayerAggregationContainsNPluginLayer(urlMappa[i].nPluginLayer);
			parametri.push({ xtype: 'hidden', 
							name: 'opacity', 
							value: lag.opacity});			
							
			var tileStampaAltezza 	= 0;
			var tileStampaLarghezza = 0;
			
			if (lag!=null && this.TOCPanel && this.TOCPanel.tocInfo!=null) {
				
				var servInfo = this.TOCPanel.tocInfo.getServer(lag.server.id);
				if (servInfo!= null) {
					tileStampaLarghezza = servInfo.tileStampaLarghezza;
					tileStampaAltezza   = servInfo.tileStampaAltezza;
				}
				
			}
			  
			parametri.push({ xtype: 'hidden', 
				name: 'tileStampaAltezza', 
				value: tileStampaAltezza});

			parametri.push({ xtype: 'hidden', 
				name: 'tileStampaLarghezza', 
				value: tileStampaLarghezza});							
									
		}
		
		var popups = this.viewer.pluginGetOpenedPopups();
		for (var j=0; j < popups.length; j++) {
			var p = popups[j];
			parametri.push({ xtype: 'hidden', 
				name: 'popupxy', 
				value: p.lonlat.lon + "|" + p.lonlat.lat});
			
			parametri.push({ xtype: 'hidden', 
				name: 'popuptext', 
				value: p.contentHTML});
			
		}
		
		var fp = Ext.create('Ext.FormPanel', {
			id: 'fp',
	        border: false,
	        frame: true,
	        items: [{
	        	xtype: 'container',	
	        	layout: 'column',
	        	border: false,
	            defaults: {
	                columnWidth: '.5',
	                border: true
	            },            
	            items: parametri
	        }]
	    });
	    
	    fp.removeLegendParams = function(){
	    	
	    	var fields = this.getForm().getFields().items;
	    	var toRemove = [];
	    	
	    	for(var f=0; f < fields.length; f++){	 	    		
	    		if(!fields[f].name) continue;	    		
	    		if((fields[f].name == 'legendLayerTitles') || (fields[f].name == 'legendGraphicUrls')){
	    			// lo registro in un array e lo rimuovo successivamente, perché se lo rimuovo al volo cambia la lunghezza dell'array medesimo e non funziona correttamente
	    			toRemove.push(fields[f]);
	    		}	    			    		
	    	}	
	    	
	    	for(var t = 0; t < toRemove.length; t++){    			
    			this.remove(toRemove[t],true);
    		}
	    }
	    
	    fp.generateLegendParams = function(){
	    	
	    	this.removeLegendParams();
	    	
	    	if(!this.down('[name=printLegend]').checked) return;
	    	
	    	var scale = 1 * this.down('[name=scala]').getValue();
	    	
	    	var legendParams = [];
	    	
	    	for (var i=urlMappa.length-1; i >= 0 ; i-- ) {
					    			    					
				// TODO gestita solo mappa 0
				var nMappa = 0;
				var lag = me.paramsJS.mapDefinitions[nMappa].whichLayerAggregationContainsNPluginLayer(urlMappa[i].nPluginLayer);				
				
				if (lag!=null && me.TOCPanel && me.TOCPanel.tocInfo!=null) {
																				
					// Codice per aggiunta url della legendGraphic
					for(var j = 0; j < lag.layers.length ; j++){
						
						var layInfo = me.TOCPanel.tocInfo.searchLayerInfo(lag.layers[j].serverID,lag.layers[j].name);
						
						// Non gestito il caso di MAPSERVER CGI
						if(	!layInfo || 
							(layInfo.classi.length > 1) || 
							lag.layers[j].hidden || 
							!lag.layers[j].checked || 
							//layInfo.raster ||
							!me.TOCPanel.layerIsVisibleAtScale(scale, lag.layers[j].scalaMinima, lag.layers[j].scalaMassima, layInfo.minScaleMin, layInfo.maxScaleMax)) continue;						
						
						var legendGraphicUrls = layInfo.classi[0].nome;
						var legendLayerTitles = layInfo.descr;
						
						legendParams.push({ xtype: 'hidden', 
								name: 'legendLayerTitles', 
								value: legendLayerTitles});														
						
						legendParams.push({ xtype: 'hidden', 
								name: 'legendGraphicUrls', 
								value: legendGraphicUrls});
								
						legendParams.push({ xtype: 'hidden', 
								name: 'legendLayerStileIndipDaScala', 
								value: layInfo.stiliIndipDaScala});
								
						legendParams.push({ xtype: 'hidden', 
								name: 'legendLayerStileIndipDaPosizione', 
								value: layInfo.stiliIndipDaPosizione});
																												
					}
															
				}				  					
										
			}
			
			this.add(legendParams);
			
	    }

		var printWindow = Ext.create('TolomeoExt.Window', {
			id: 'printWindow',
			title: ToloI18n.getMsg("ToloMapAPIExt.printWindow.title"),
			layout: 'fit',
			iconCls: 'iconPrint',
			frame: true,
			border: false,
			constrain: true,
			maximizable: false,
	//		monitorResize: true,
			plain: true,
			modal: true,
			width: 600,
			height: 580,
			items: fp, //printWizard
			buttonAlign: 'right',
			buttons: [{
	            text: ToloI18n.getMsg("ToloMapAPIExt.printWindow.btnOK"),
	            width: 75,
	            handler: function(){
	            	if(fp.getForm().isValid()){
	            		//getForm().
	               		Ext.getCmp('fp').getForm().standardSubmit = true;
	               		//Ext.getCmp('fp').getForm().getEl().dom.acceptCharset = 'utf-8';
	               		//Ext.getCmp('fp').getForm().getEl().dom.target = '_self';
	               		//Ext.getCmp('fp').getForm().getEl().dom.action = server + context + '/StampaMappaServlet';
	               		var submitParams = {
	               					headers: { acceptCharset: 'utf-8' },
	               					target: '_self',
	               					url: server + context + '/StampaMappaServlet',
	               					paramPreset: me.paramsJS.nomePreset
	               		}
	               		
	               		// Aggiunta parametri WMS da url
						Ext.apply(submitParams, me.paramsJS.urlAdditionalParams);						
						
						if(fp.down('[name=printPermalink]').getValue()){
							fp.down('[name=permalinkHref]').setValue(me.generatePermalink());
						}
	               		
						fp.generateLegendParams();
	               		fp.getForm().submit(submitParams);
	            	}
	            }
	        },{
	        	text: ToloI18n.getMsg("ToloMapAPIExt.printWindow.btnAnnulla"),
	            width: 75,
	            handler: function(){
					Ext.getCmp('printWindow').close();
				}
	        }]
		}).show();
	},
	
	languageChange: function(lng){
		var obj = Ext.Object.fromQueryString(window.location.search);
		obj.lang = lng;
		window.location = (window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '')) + window.location.pathname + "?" + Ext.Object.toQueryString(obj);
	}, 
	
	/**
	 * Method: wmsExplorerWidgetActivate
	 * Attivazione widget di gestione aggiunta WMS
	 * 
	 * @param {} addPointCatIdx
	 * @param {} addPointLayIdx
	 * @param {} bBefore
	 */
	wmsExplorerWidgetActivate: function(addPointCatIdx, addPointLayIdx, bBefore) {
		
		if(this.paramsJS.layOut.WMSExplorer && !this.wmsExplorerWidget){	
		
			var me = this;
			
			this.wmsExplorerWidget = Ext.create('TolomeoExt.Window',{
				layout: 'fit',
		        closeAction: 'hide',
				title: ToloI18n.getMsg("ToloMapAPIExt.WMSExplorer.title"),
				resizable: true,
				constrain: true,
				width: 600, 
				height: 400,
				items: [
				        Ext.create('TolomeoExt.ToloWMSExplorerPanel', {
				        		addPointCatIdx: (addPointCatIdx) ? addPointCatIdx : "0",
	 							addPointLayIdx: (addPointLayIdx) ? addPointLayIdx : undefined,
	 							bBefore: bBefore,
	 							listeners: {
	 								'addLayer' : function(layers) {
		 									for (var i=0; i<layers.length; i++) {
		 										var layer = layers[i];
			 									var options = {
															serverurl:  layer.url,
			 												layername: layer.name,
			 												addPointCatIdx: this.addPointCatIdx,
			 												addPointLayIdx: this.addPointLayIdx,
			 												bBefore: this.bBefore
														}
														me.addLayer(options);
		 									}
	 									},
	 								'closePressed': function() {
	 										me.wmsExplorerWidget.hide();	
	 										me.buttonsPanel.buttonToggle(TolomeoExt.ToloAPIOpCodes.btnWMSExplorer, null, true)
	 								}
	 							}
				        	})],
				 listeners: {'hide' : function() {
										me.buttonsPanel.buttonToggle(TolomeoExt.ToloAPIOpCodes.btnWMSExplorer, null, true)
									}
				 			}
			}).show();

		} else{
			if (addPointCatIdx) this.wmsExplorerWidget.addPointCatIdx = addPointCatIdx;
 			if (addPointLayIdx) this.wmsExplorerWidget.addPointLayIdx = addPointLayIdx;
 			if (bBefore) this.wmsExplorerWidget.bBefore = bBefore;
			this.wmsExplorerWidget.show();
		}
		
	},
	
	/**
	 * Disattivazione widget di gestione aggiunta WMS
	 */
	cswWidgetDeactivate : function(){
		if(this.cswWidget){
			this.cswWidget.hide();
		}
	},
	
	/**
	 * Method: wmsExplorerWidgetDeactivate
	 * Chiude il componente di gestione dei Catalog Services.
	 */
	wmsExplorerWidgetDeactivate: function(){
		if(this.wmsExplorerWidget){
			this.wmsExplorerWidget.hide();
		}
	},
	
	/**
	 * Method: cswWidgetActivate
	 * Crea una finestra di gestione dei Catalog Services.
	 *
	 * 
	 */
	cswWidgetActivate : function(addPointCatIdx, addPointLayIdx, bBefore) {
		
		var cswCrsCode = "EPSG:4326";		
		var f = function(){
			
			var cswConfig = this.paramsJS.layOut.csw;
			
			if(!this.cswWidget){			
	
				var toloBBox = BBox.create(this.viewer.pluginGetMapExtent());
				
				var currCrsCode = this.getProjectionCode();
						
				if(currCrsCode != cswCrsCode){
					toloBBox.transform(currCrsCode,cswCrsCode);						
				}
				
				var config = {			
					XDProxy: { url:this.TOLOMEOServer + this.TOLOMEOContext + "/TolomeoProxyServlet", callback: "" },
					//TODO ricorda di mettere a posto. Sembra che se c'e' anche il server http:// non funzioni bene e che parte un options invece di un get
					//XDProxy: { url:"/tolomeobinj/TolomeoProxyServlet", callback: "" },	
					catalogs : cswConfig.catalogList,			   
			     	dcProperty: "title",
				   
				    initialBBox: {
						minx: Math.min(toloBBox.left,toloBBox.right),
						miny: Math.min(toloBBox.bottom,toloBBox.top),
						maxx: Math.max(toloBBox.left,toloBBox.right),
						maxy: Math.max(toloBBox.bottom,toloBBox.top)
					}, 
			
			   		cswVersion: cswConfig.cswVersion,  		  		
					filterVersion: cswConfig.filterVersion,  		
					start: 1,  		
					limit: cswConfig.limit,		
					timeout: cswConfig.timeout
				};
					
				/*
				var i18n = Ext.create('Ext.i18n.Bundle', {
					bundle : "CSWViewer",
					path : this.TOLOMEOServer + this.TOLOMEOStaticRoot + "js/ext/csw/i18n",
					lang : "it-IT"
				});*/
				
				
				//var i18n = TolomeoExt.getApplication().bundle;
				
				
				var me = this;
			
				//i18n.onReady( function() {
				//i18n.on('loaded', function() { 
					
					// Declares a panel for querying CSW catalogs
					var cswPanel = new CSWPanel({
							title: "",
							header: false,
							config: config,
							region:'center',
							i18n: ToloI18n,
							addPointCatIdx: (addPointCatIdx) ? addPointCatIdx : "0",
	 						addPointLayIdx: (addPointLayIdx) ? addPointLayIdx : undefined,
	 						bBefore: bBefore,
							listeners: {
								'zoomToExtent': function(el){
										
										// il bound ritornato da geonetwork ha left e right invertito, per evitare problemi...
										var b = {
											left: Math.min(el.bbox.left, el.bbox.right),
											bottom: Math.min(el.bbox.bottom, el.bbox.top),
											right: Math.max(el.bbox.left, el.bbox.right),
											top: Math.max(el.bbox.bottom, el.bbox.top)
										};
									
										var toloBBox = BBox.create(b);
										var currCrsCode = me.getProjectionCode();					
										if(currCrsCode != cswCrsCode){
											toloBBox.transform(cswCrsCode,currCrsCode);						
										}
										me.zoomToExtent(toloBBox,null);
									},
							
								'viewMap': function(el){
									// addPointCatIdx, addPointLayIdx, bBefore
									if(el.layers){
										for(var l=0; l < el.layers.length; l++ ){
											var layer = el.layers[l];
											if(layer.wms){
												var options = {
													serverurl:  layer.wms,
	 												layername: layer.layer,
	 												addPointCatIdx: this.addPointCatIdx,
	 												addPointLayIdx: this.addPointLayIdx,
	 												bBefore: this.bBefore
												}
												me.addLayer(options);
												/*
												var mappa = {
													mapOptions : "layers: '" + layer.layer + "'",
													overlay : false,
													SRID : me.getProjectionCode(),
													units : 'm',
													mostraInLegenda : true,
													viewerOptions : "",
													typeCode : 11,		// WMS
													nome : layer.description,
													url : layer.wms
												};
												me.addLayer(mappa);
												*/
											}
										}
									}
								},
							
								'beforesearch' : function(params){
									if(!(params.useAdvancedSearch && params.useBbox)) return;
							
									var toloBBox = BBox.create(me.viewer.pluginGetMapExtent());					
									var currCrsCode = me.getProjectionCode();
									
									if(currCrsCode != cswCrsCode){
										toloBBox.transform(currCrsCode,cswCrsCode);						
									}
									
									var cswBBox = {									
										minx: Math.min(toloBBox.left,toloBBox.right),
										miny: Math.min(toloBBox.bottom,toloBBox.top),
										maxx: Math.max(toloBBox.left,toloBBox.right),
										maxy: Math.max(toloBBox.bottom,toloBBox.top)
									}
									
									this.setBBox(cswBBox);
								}
						}
							
					});
			
					cswPanel.mon(this.TOCPanel, 'itemSelected', function(catTreeIdx, layTreeIdx, classi) {
														cswPanel.addPointCatIdx = catTreeIdx;
									 					cswPanel.addPointLayIdx = (layTreeIdx) ? layTreeIdx : undefined;
													});
													
					me.cswWidget = Ext.create('Ext.Window', {
						id: 'cswWindow',
						title: ToloI18n.getMsg("ToloMapAPIExt.CSWWidget.title"),
						layout: 'fit',
						iconCls: 'iconCsw',
						frame: true,
						border: false,
						maximizable: false,
						constrain: true,
						minimizable: false,
				//		monitorResize: true,
						plain: true,
						width : 620,				
						boxMaxHeight:562,
						boxMinWidth: 600,
		            	autoScroll: true,
		            	closeAction: 'hide',
						cls: 'clearCSS',
						cswPanel: cswPanel, 
						items: [cswPanel],
						listeners : {
							'hide' : function() {
								me.buttonsPanel.buttonToggle(TolomeoExt.ToloAPIOpCodes.btnCsw, null, true)
							}
						}
					});
										
					me.cswWidget.show();
			//	});
			}else{
				if (addPointCatIdx) this.cswWidget.cswPanel.addPointCatIdx = addPointCatIdx;
	 			if (addPointLayIdx) this.cswWidget.cswPanel.addPointLayIdx = addPointLayIdx;
	 			if (bBefore) this.cswWidget.cswPanel.bBefore = bBefore;
				this.cswWidget.show();
			}
		}
		
		this.lazyLoadScript(['proj4js', 'cswExplorer'],
			f,
			function(){Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.LazyLoad.alert.title"), ToloI18n.getMsg("ToloMapAPIExt.LazyLoad.alert.msg"), function(){this.buttonsPanel.buttonToggle(TolomeoExt.ToloAPIOpCodes.btnCsw, null, true);}, this);},
			this
		);
					
	},
	
	/**
	 * Aggiunge un layer nella posizione indicata dai parametri.
	 * 
	 * @param {} options oggetto contenente le opzioni nei seguenti attributi <br />
	 * 		<ul>
	 * 			<li>serverurl: url del server WMS</li>
	 * 			<li>layername: nome del layer WMS</li>
	 * 			<li>addPointCatIdx: Indice della categoria nella quale viene aggiunto il layer </li>
	 * 	 		<li>addPointLayIdx: Indice layer prima o dopo del quale aggiungere il nuovo layer</li>
	 * 			<li>bBefore: indica se aggiungere prima o dopo</li>
	 * 		</ul>
	 * 			
	 */
	addLayer: function (options) {
		
		if (this.TOCPanel) {
			this.TOCPanel.addLayer(options);
		}
		
	},
	
	/**
	 * Method: setCurrentSelectLayer
	 * Setta il layer corrente (codTPN). 
	 *
	 * Parameters:
	 * layer - {} il layer.
	 */
	setCurrentSelectLayer: function (layer) {
		this.currentSelectedLayer = layer;
		this.togglePermittedOperations();
		this.fireEvent('onOperationPressDefault', 2);
	},
	
	/**
	 * Method: getCurrentSelectLayer
	 * 
	 * Returns:
	 * Ritorna l'oggetto ParametriEventiLayer relativo al layer scelto in combobox selectLayerChoose
	 */
	getCurrentSelectLayer: function () {
		if ((this.paramsJS.azioniApertura.modoEditingSingolo == null) ||(this.paramsJS.azioniApertura.modoEditingSingolo == ""))  {
			if(this.currentSelectedLayer==null) return null;
			return this.paramsJS.getParamJSLayer(this.currentSelectedLayer);
		} else {
			var ret = this.paramsJS.getParamJSLayer(this.paramsJS.azioniApertura.modoEditingSingolo.layerCODTPN);
			if (ret) return ret;
		}
		// non dovrebbe arrivare fino a qua a meno che non sia modoEditSingolo ed il corrispondente layer non ha azioni definite
		alert(ToloI18n.getMsg("ToloMapAPIExt.getCurrentSelectLayer.error",{LAYER: this.paramsJS.azioniApertura.modoEditingSingolo.layerCODTPN}));
		return null;
	},
			
	/**
	 * Method: onAnnullaSelezioni
	 * 
	 */
	onAnnullaSelezioni: function() {
		this.clearSelected(true);
		this.clearHighLigthed(true);
	},

	/**
	 * Method: onIdentify
	 * Esegue identify dell'oggetto correntemente selezionato, invocando la doEventActions con gli appositi parametri
	 */
	onIdentify: function () {	
		var azSelLayer = this.getCurrentSelectLayer();
		this.identify(azSelLayer);
		/*
		this.geoOpToPostVar(this.operationIdentify);
		this.geometryToPostVar ("");
		//ALE1
		// suppongo che un elemento del giusto layer sua selezionato altrimenti non sarebbe attivo il pulsante
		if(this.selezioneCorrente.getByCodTPN(azSelLayer.codTPN)){
			this.doEventActions(azSelLayer, this.eventVis,  this.selezioneCorrente.getByCodTPN(azSelLayer.codTPN).geometries[0].key);
			if (azSelLayer.chiudiSuDblClick) {
				close();
			}
		}
		*/
	},
	
	identify: function (layer){
		this.geoOpToPostVar(this.operationIdentify);
		this.geometryToPostVar ("");

		if(this.selezioneCorrente.getByCodTPN(layer.codTPN)){
			var selCorrente = this.selezioneCorrente.getByCodTPN(layer.codTPN).geometries[0];
			this.doEventActions(layer, this.eventVis,  selCorrente.key, undefined, undefined, undefined, selCorrente);
			
			if (layer.chiudiSuDblClick) {
				close();
			}
		}
	},

	/**
	 * Method: onCustomButtonPress
	 *
	 * Parameters:
	 * btn - {} il pulsante premuto.
	 */
	onCustomButtonPress: function (btn) {	
	
		//paramsJS.azioniEventi.eventiLayerList[layerPos].azioniEventiRicercaList.ricercaList[ricercaPos]
		var idBtn = btn.idCustomButton;
	
		//var cb = this.paramsJS.layOut.customButtonList[idBtn];
		if (((typeof(btn.pressFunction)=="undefined"))||(btn.pressFunction == '')) {
			var currLayer = this.getCurrentSelectLayer();
			
			if (currLayer!=null) { 
				this.geoOpToPostVar("");
				this.geometryToPostVar ("");
				var selCorrente = this.selezioneCorrente.getByCodTPN(currLayer.codTPN);
				var key = selCorrente != null ? selCorrente.geometries[0].key : null;
				this.doEventActions(currLayer, this.eventCustomButton, key, null, null, idBtn, undefined, undefined, selCorrente);
			} else {
				alert(ToloI18n.getMsg("ToloMapAPIExt.onCustomButtonPress.nolayer"));
			}
		} else {
			(new Function(btn.pressFunction)).call(this);
			//btn.pressFunction();			
		}
		
	},
	
	/**
	 * Method: onCustomButtonRelease
	 *
	 * Parameters:
	 * btn - {} il pulsante rilasciato.
	 */
	onCustomButtonRelease: function (btn) {	
		//paramsJS.azioniEventi.eventiLayerList[layerPos].azioniEventiRicercaList.ricercaList[ricercaPos]
		//var idBtn = btn.idCustomButton;
	
		//var cb = this.paramsJS.layOut.customButtonList[idBtn];
		if (((typeof(btn.releaseFunction)=="undefined"))||(btn.releaseFunction == '')) {
		//if (((btn.releaseFunction == null)||(btn.releaseFunction == ''))) {
				
		} else {
			(new Function(btn.releaseFunction)).call(this);
			//btn.releaseFunction();			
		}		
	},
	
	nuovoDaLayerStart: function() {
		var	layer = this.getCurrentSelectLayer();
		// Ricerca su selezione corrente le geometrie appartenenti ai layer che possono essere inserite sul layer corrente
		var jsGeometryList = new JSGeometryArray();
		var codTPNList = layer.azioniEventiInsFromLayer.enabledLayerList;
		for (var i=0; i< codTPNList.length ; i++) {
			var buff = this.selezioneCorrente.getByCodTPN(codTPNList[i].codTPN);
			jsGeometryList.add(buff);
		}
		var insFromLayerPanel = new TolomeoExt.ToloInsFromLayerPanel({
												jsGeometryList: jsGeometryList
												});
		
		
		insFromLayerPanel.on("geompartitemmouseenter", 
				function(record) {
				this.addHighlighted(record.get("val"));
			},
			this);
		
		insFromLayerPanel.on("geompartitemmouseleave", 
				function(record) {
				this.clearHighLigthed();
			},
			this);
				
		// Mostra finestra per scelta geometrie da inserire e per conferma
    	var insFromLayerWin =  Ext.create("Ext.Window",{
    		width: 300,
    		height: 300,
    		layout: 'fit',
    		constrain: true,
    		modal:true,
    		items: [insFromLayerPanel]
    		
    	});

		insFromLayerPanel.on("exitCancel", 
				function() {
					insFromLayerWin.close();
			},
			this);
    	
		insFromLayerPanel.on("exitOk", 
				function(geom, parts, bAll) {
					insFromLayerPanel.mask("attendere prego...");
					// Inizializza in postVar il tipo di operazione
					this.geoOpToPostVar(this.digitizeOperationInsertFromLayer);
					// Inizializza in postVar la geometria originale
					this.geometryToPostVar (geom);
					//Inizializza in postVar la/le geometrie da inserire
					this.geomPartsToPostVar(parts);
					//Inizializza in postVar il flag che indica se le geometrie sono tutte
					this.geomPartsAllFlagToPostVar(bAll);
					// Invoca la DoEventActions
					this.doEventActions(layer, this.eventInsFromLayer, null);
					// Chiude la finestra
					insFromLayerWin.close();
			},
			this);
		
		insFromLayerWin.show();
		
		
		
	},
	
	nuovoDaLayerStop: function(){
		
	},
	
	nuovoDaImportStart: function() {
		var thisPanel = this;
		var	layer = this.getCurrentSelectLayer();
		
		var tipoGeomDescr = '';
		switch (layer.tipoGeometria){
		  case 1: tipoGeomDescr = ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.tipoGeom.punti");
			break;
		  case 2: tipoGeomDescr = ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.tipoGeom.linee");
			break;
		  case 3: tipoGeomDescr = ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.tipoGeom.poligoni");
		   	break;
		}
		/*
		var labelTextTmpl = 'Scegli un file:<br/>'+
							'- compresso formato zip contenente shapefiles<br />' +
							'- dimensione massima: {0} MB<br />' +
							'- dimensione massima totale dei file contenuti: {1} MB<br />' +
							'- contenente esclusivamente {2}<br />'+
							'- contenente massimo {3} shapefile<br />' + 
							'- contenente complessivamente al massimo {4} geometrie<br />' +
							'- sistema di riferimento dei dati: {5}<br />' +
							'- contenente geometrie totalmente comprese all\'interno della coordinate<br/>{6}';
		
		var labelText = Ext.String.format(labelTextTmpl ,
				this.TOLOMEOServerSettings.importGeomUploadMaxSize, 
				this.TOLOMEOServerSettings.importGeomUploadUncompressedMaxSize,
				tipoGeomDescr,
				this.TOLOMEOServerSettings.importGeomUploadShpMaxNumber, 
				this.TOLOMEOServerSettings.importGeomUploadGeomsMaxNumber,
				this.paramsJS.mappe.SRID,
				'('+this.paramsJS.mappe.maxExtentLeft + ' ' +  this.paramsJS.mappe.maxExtentBottom + ' '+ this.paramsJS.mappe.maxExtentRight + ' ' + this.paramsJS.mappe.maxExtentTop +')');
		*/
		
		var labelText = ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.msg", {
			importGeomUploadMaxSize: this.TOLOMEOServerSettings.importGeomUploadMaxSize, 
			importGeomUploadUncompressedMaxSize: this.TOLOMEOServerSettings.importGeomUploadUncompressedMaxSize,
			tipoGeomDescr: tipoGeomDescr,
			importGeomUploadShpMaxNumber: this.TOLOMEOServerSettings.importGeomUploadShpMaxNumber, 
			importGeomUploadGeomsMaxNumber: this.TOLOMEOServerSettings.importGeomUploadGeomsMaxNumber,
			SRID: this.paramsJS.mappe.SRID,
			bbox: '('+this.paramsJS.mappe.maxExtentLeft + ' ' +  this.paramsJS.mappe.maxExtentBottom + ' '+ this.paramsJS.mappe.maxExtentRight + ' ' + this.paramsJS.mappe.maxExtentTop +')'
		});
		
		var formpanel = Ext.create('Ext.form.Panel', {
			url: this.TOLOMEOServer + this.TOLOMEOContext + '/ToJSGeometryServlet',
			bodyPadding: 10,
		    frame: true,
		    items: [{
		        xtype: 'filefield',
		        name: 'uploadfield',
		        allowBlank: false,
		        //blankText: "Seleziona un file .zip contentente gli shapefile da importare ",
		        labelAlign: 'top',
		        labelStyle: 'margin-bottom: 5px ',
		        fieldLabel: labelText,
		        labelSeparator: '',
		        //labelWidth: 50,
		        buttonText: ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.btnImporta"),
		        anchor: '100%',
		        regex: /\.zip$/i,
		        regexText: ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.regexText"),
		        msgTarget: 'under',
		        listeners:{
		            afterrender:function(cmp){
		              cmp.fileInputEl.set({
		                accept:'.zip,.ZIP' // or w/e type
		              });
		            }
		        },/*
		        reset: function () {
		            var me = this,
		                clear = me.clearOnSubmit;
		            if (me.rendered) {
		                me.button.reset(clear);
		                me.fileInputEl = me.button.fileInputEl;
		                me.fileInputEl.set({
		                    accept: '.zip,.ZIP,.txt'
		                });
		                if (clear) {
		                    me.inputEl.dom.value = '';
		                }
		                me.callParent();
		            }},*/
				buttonConfig: {
					text: ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.btnScegli"),
			        disabled: false,
			        iconCls: 'iconConferma',
			        //width: 75,
			        tooltip : {text: 'Scegli'}
				},
				buttonOnly: false},
				{ xtype: 'hidden', 
					 name: 'bbox', 
					 value: this.paramsJS.mappe.maxExtentLeft + ' ' +
					 	    this.paramsJS.mappe.maxExtentBottom + ' '+
					 	    this.paramsJS.mappe.maxExtentRight + ' ' +
					 	    this.paramsJS.mappe.maxExtentTop},
		 	   { xtype: 'hidden', 
					 name: 'tipoGeometria', 
					 value: layer.tipoGeometria }
				],
			buttons: [{
			        text: ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.btnChiudi"),
			        handler: function() {
			        	formpanel.up('window').close();
			        }
			    }, {
			        text: ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.btnInvia"),
			        formBind: true, //only enabled once the form is valid
			        disabled: true,
			        handler: function() {
			            var form = formpanel.getForm();
			            if (form.isValid()) {
			                form.submit({
			                	scope: thisPanel,
			                    success: function(form, action) {this.nuovoDaImportLoadSuccess(formpanel, action);},
			                    failure: function(form, action) {
			                    	
			                    	if (action.failureType === Ext.form.action.Action.CONNECT_FAILURE) {
			                            Ext.Msg.alert('Errore', action.response.responseText);
			                        }
			                        if (action.failureType === Ext.form.action.Action.SERVER_INVALID){
			                            // server responded with success = false
			                        	if (action.result && action.result.rows){
			                        		Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.errimp.title"), action.result.rows[0].msgErrore);
			                        	} else {
			                        		Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.err.title"), action.response.responseText);
			                        	}
			                        }
			                    	
			                        formpanel.up('window').close();
			                    }
			                });
			            }
			        }
			    }]});
		        
		Ext.create('Ext.window.Window',{
			width: 500,
			resizable: false,
			height: 300,
			constrain: true,
			modal:true,
			layout: 'fit',
			title: ToloI18n.getMsg("ToloMapAPIExt.nuovoDaImportStart.win"),
			items: [formpanel]
		}).show();
	},
	
	nuovoDaImportLoadSuccess: function(formpanel, action){
		
		var a = Ext.decode(action.response.responseText);
		var	layer = this.getCurrentSelectLayer();
		
		var store = new Ext.data.JsonStore({
		    proxy: {
		        type: 'memory',
		        reader: {
		            type: 'json'
		        }
		    },
		    data: a
		});
		
		store.load({
			scope: this,
			callback: function(records, loadOptions, success) {
				var geoms = new JSGeometryArray();
				geoms.FromStore(records, store);
				this.addHighlighted(geoms);
				this.zoomToHighlighted(null, 200);
				
				switch(geoms.size){
				case 0: // TODO gestire se ==0
					break;
				case 1:
					this.addSelected(geoms, false);
					break;
				default: 
					break;
				}
				
				
				var selectPanel = new TolomeoExt.ToloSelectGeoms({
					jsGeometryList: geoms
					});

				selectPanel.on("geomItemClick", 
						function(geom) {
							this.addHighlighted(geom);
							this.zoomToHighlighted(null, 200);
						},
				this);

				selectPanel.on("mostraPressed", 
						function() {
							this.zoomToHighlighted(null, 200);
						},
						this);
				/*
				selectPanel.on("selectNonePressed", 
						function() {
							this.clearHighLigthed();
						},
						this);
				
				selectPanel.on("selectAllPressed", 
						function() {
							this.addHighlighted(geoms);
						},
						this);
				*/
				selectPanel.on("selectedGeomsChange", 
						function(selGeoms) {
							this.clearHighLigthed();
							if (selGeoms.size()>0) this.addHighlighted(selGeoms);
						},
						this);

				// Mostra finestra per scelta geometrie da inserire e per conferma
				var selectWin =  Ext.create("Ext.Window",{
					width: 300,
					height: 300,
					layout: 'fit',
					constrain: true,
					modal:true,
					items: [selectPanel]				
				});

				selectPanel.on("exitCancel", 
						function() {
							this.clearHighLigthed();
							selectWin.close();
						},
						this);

				selectPanel.on("exitOk", 
						function(geom) {
							selectPanel.mask("attendere prego...");

							// Inizializza in postVar il tipo di operazione
							this.geoOpToPostVar(this.digitizeOperationInsertFromImport);
			
							// Inizializza in postVar la geometria originale
							this.geometryToPostVar (geom);
						
							// Invoca la DoEventActions
							this.doEventActions(layer, this.eventInsFromImport, null);
			
							this.clearHighLigthed();
							
							// Chiude la finestra
							selectWin.close();
					},	this);

				selectWin.show();

				formpanel.up('window').close();
			
			}
		});
		
		
		
		
				
		
	},
	
	nuovoDaImportStop: function(){
		
	},
	
	
	/**
	 * Method: onDigitizeStart
	 * Funzione per l'inizio della digitalizzazione.
	 *
	 * Parameters:
	 * digitizeOperation - {String} tipo di digitalizzazione richiesta (vedere costanti all'inizio della pagina paer valori possibili).
	 */
	onDigitizeStart: function (digitizeOperation) {
		
		this.currentDigitizeOperation = digitizeOperation;
		switch (digitizeOperation) {
	   		case this.digitizeOperationInsert:
	   			this.onDigitizeStartInsert();
	   		break;
	   		case this.digitizeOperationSubtract:
	   			this.onDigitizeStartSubtract();
	   		break;
	   		case this.digitizeOperationAdd:
	   			this.onDigitizeStartAdd();
	   		break;
	   		case this.digitizeOperationAddSub:
	   			this.onDigitizeStartAddSub();
	   		break;
	   		case this.digitizeOperationVertexEdit:
	   			this.onDigitizeStartVertexEdit();
	   		break;
	   		case this.digitizeOperationDragDrop:
	   			this.onDigitizeStartDragDrop();
	   		break;
	   	}
	},
		
	/**
	 * Method: onDigitizeStop
	 * Funzione per l'interruzione (annullamento) della digitalizzazione.
	 *
	 * Parameters:
	 * digitizeOperation - {String} digitizeOperation, tipo di digitalizzazione richiesta (vedere costanti all'inizio della pagina paer valori possibili).
	 */
	onDigitizeStop: function (digitizeOperation) {

		this.currentDigitizeOperation = digitizeOperation;
		switch (digitizeOperation) {
	   		case this.digitizeOperationInsert:
	   			this.onDigitizeStopInsert();
	   		break;
	   		case this.digitizeOperationSubtract:
	   			this.onDigitizeStopSubtract();
	   		break;
	   		case this.digitizeOperationAdd:
	   			this.onDigitizeStopAdd();
	   		break;
	   		case this.digitizeOperationAddSub:
	   			this.onDigitizeStopAddSub();
	   		break;
	   		case this.digitizeOperationVertexEdit:
	   			this.onDigitizeStopVertexEdit();
	   		break;
	   		case this.digitizeOperationDragDrop:
	   			this.onDigitizeStopDragDrop();
	   		break;
	   	}
	},
	
	/**
	 * Method: onDigitizeByCADStart
	 * Funzione per l'inizio della digitalizzazione per mezzo del CAD
	 *
	 * Parameters:
	 * digitizeOperation - {String} tipo di digitalizzazione richiesta (vedere costanti all'inizio della pagina paer valori possibili).
	 */
	onDigitizeByCADStart: function (digitizeOperation) {
		
		this.currentDigitizeOperation = digitizeOperation;
		switch (digitizeOperation) {
	   		case this.digitizeOperationInsert:
	   			this.onDigitizeByCADStartInsert();
	   		break;	   		
	   	}
	},
	
	/**
	 * Method: onDigitizeByCADStop
	 * Funzione per l'interruzione (annullamento) della digitalizzazione inizia per mezzo del CAD
	 *
	 * Parameters:
	 * digitizeOperation - {String} digitizeOperation, tipo di digitalizzazione richiesta (vedere costanti all'inizio della pagina paer valori possibili).
	 */
	onDigitizeByCADStop: function (digitizeOperation) {

		this.currentDigitizeOperation = digitizeOperation;
		switch (digitizeOperation) {
	   		case this.digitizeOperationInsert:
	   			this.onDigitizeByCADStopInsert();
	   		break;	   		
	   	}
	},

	/**
	 * Method: onUpdateAlfa
	 * Funzione chiamata alla fine della modifica alfanumerica. Innesca l'esecuzione delle azioni collegate a tale evento
	 */
	onUpdateAlfa: function () {
		var modLayer = this.getCurrentSelectLayer();
		this.geoOpToPostVar(this.operationUpdateAlfa);
		this.geometryToPostVar ("");
		//ALE1
		// suppongo che un elemento del giusto layer sua selezionato altrimenti non sarebbe attivo il pulsante
		var selCorrente = this.selezioneCorrente.getByCodTPN(modLayer.codTPN).geometries[0];
		this.doEventActions(modLayer, this.eventUpdateAlpha,  selCorrente.key, undefined, undefined, undefined, selCorrente);        
		this.clearSelected(modLayer.codTPN);
	},

	/**
	 * Method: onDelete
	 * Funzione chiamata per la cancellazione di un oggetto. Innesca l'esecuzione delle azioni collegate a tale evento. 
	 * Nel file xml l'azione vuota (default) provvede alla cancellazione dell'oggetto.
	 */
	onDelete: function () {

		var cancLayer = this.getCurrentSelectLayer();
		var messint = ToloI18n.getMsg("ToloMapAPIExt.onDelete.msg", {descrizioneLayer:cancLayer.descrizioneLayer});
		
		if (confirm(messint)) {			

			this.geoOpToPostVar(this.operationFeatureDelete);
			this.geometryToPostVar ("");
			//ALE1
			// suppongo che un elemento del giusto layer sua selezionato altrimenti non sarebbe attivo il pulsante
			var selCorrente = this.selezioneCorrente.getByCodTPN(cancLayer.codTPN).geometries[0];
			
			this.doEventActions(cancLayer, this.eventCanc,  selCorrente.key, undefined, undefined, undefined, selCorrente);
			
			var azioniEventi = this.getAzioniEventi(cancLayer,this.eventCanc, false);
			var redraw = true
			if(azioniEventi){
				redraw = azioniEventi.refreshAtTheEnd;
			}
			this.clearSelected(redraw, cancLayer.codTPN);
			
		} 
		
	},

	/**
	 * Method: onSelectLayerChange
	 * Funzione invocata ad ogni cambio del layer selezionato per le operazioni di editing. Provvede a chiamare le funzioni necessarie per aggiornare lo stato del sistema a questa nuova situazione
	 */
	// Chiamata da JSP quando viene cambiato il layer sul quale si vuole fare la selezione
	onSelectLayerChange: function () {
		// Modifica di conseguenza le operazioni possibili (icone)
		this.togglePermittedOperations();
	},

	// Funzioni che devono essere chiamate dal plugin alla fine della digitalizzazione

	/**
	 * Method: onDigitizeEndVertexEditing
	 * Funzione richiamata dal viewer alla fine dell'editing vertici 
	 *
	 * Parameters:
	 * geometry - {} la geometria.
	 */
	onDigitizeEndVertexEditing: function (geometry) {
		this.onDigitizeEndGeometry(geometry);
	},

	/**
	 * Method: onDigitizeEndDragDrop
	 * Funzione richiamata dal viewer alla fine del drag-drop 
	 *
	 * Parameters:
	 * geometry - {} la geometria.
	 */
	onDigitizeEndDragDrop: function (geometry) {
		this.onDigitizeEndGeometry(geometry);
	},

	/**
	 * Method: onDigitizeEndPolygon
	 * Funzione richiamata dal viewer alla fine della digitalizzazione di un poligono
	 *
	 * Parameters:
	 * geometry - {JSGeometry} la geometria.
	 */
	onDigitizeEndPolygon: function (geometry) {
		this.onDigitizeEndGeometry(geometry);
	},

	/**
	 * Method: onDigitizeEndCircle
	 * Funzione richiamata dal viewer alla fine della digitalizzazione di un cerchio
	 *
	 * Parameters:
	 * geometry - {JSGeometry} il centro.
	 * radius - {} il raggio.
	 */
	onDigitizeEndCircle: function (center, radius) {},

	/**
	 * Method: onDigitizeEndLine
	 * Funzione richiamata dal viewer alla fine della digitalizzazione di una linea
	 *
	 * Parameters:
	 * geometry - {JSGeometry} la geometria.
	 */
	onDigitizeEndLine: function (geometry) {
		this.onDigitizeEndGeometry(geometry);
	},

	/**
	 * Method: onDigitizeEndPoint
	 * Funzione richiamata dal viewer alla fine della digitalizzazione di un punto
	 *
	 * Parameters:
	 * geometry - {JSGeometry} la geometria.
	 */
	onDigitizeEndPoint: function (geometry) {
		
		this.onDigitizeEndGeometry(geometry);
	},

	/**
	 * Method: onMappaViewChanged
	 * Funzione richiamata dal viewer quando la visualizzazione cambia per quanche motivo
	 */
	onMappaViewChanged: function () {
		this.smallMapSetPosition();
	},

	/**
	 * Method: onMappaSelect
	 * Funzione che il viewer deve chiamare quando in modalità selezione e 
	 * viene fatto click sulla mappa	
	 *
	 * Parameters:
	 * point - {Point} point, Punto clickato sulla mappa (in coordinate).
	 * selectionMode - {String} modalità di selezione ["firstOnTop","allStacked"]
	 * addToSelected - {Boolean} true per aggiungere alle selezioni già presenti (vale per layers diversi)
	 * visualize - {Boolean} true per visualizzare sul data panel le informazioni correlate alla selezione fatta
     * mapXPixel - {Number} coordinata x in pixel cliccata sulla mappa
     * mapYPixel - {Number} coordinata y in pixel cliccata sulla mappa
	 * codTpnToForceSelection - {Number} codTPN su cui forzare la selezione se si è scelto un selectionMode
	 */
	onMappaSelect: function (point,selectionMode,addToSelected, visualize, mapXPixel, mapYPixel,codTpnToForceSelection) {

		// TODO supportata solo mappa 0
		var nmappa = 0;
		var mappa = this.paramsJS.mappe.mappaList[nmappa];
		var codTPN;
		var additionalWMSLayers = [];
		
		// Se è impostata una modalità di selezione controllo legenda e/o lista layers interrogabili
		if(selectionMode || codTpnToForceSelection){
			// Se c'è la legenda l'impilamento dipende dai layer visibili su di essa
			if(this.TOCPanel){
				
				var queryableLayers = [];
				
				// Se si è chiesto di forzare la selezione su un un certo layer non considero gli altri selezionabili 
				if(codTpnToForceSelection){
					
					if(this.paramsJS.isSelectable(codTpnToForceSelection)){
						queryableLayers.push(codTpnToForceSelection);
						
						// Se il layer chiesto è selezionabile, ma non visibile lo accendo
						if(!this.TOCPanel.layerIsVisible(codTpnToForceSelection)){
							this.TOCPanel.setLayerVisibility(codTpnToForceSelection);
						}
					}
										
				} else {
					
					var visibleLayers = this.TOCPanel.getVisibleLayers();				
					
					for(var i=0; i<visibleLayers.length; i++){
						var visibleLayer = visibleLayers[i];
						if (this.paramsJS.isSelectable(visibleLayer.codTPN)){
							if ((queryableLayers.indexOf(visibleLayer.codTPN)==-1) &&
								 !visibleLayer.isUserLayer ){
									queryableLayers.push(visibleLayer.codTPN);
							}
						}
					}
					
				}

				// Aggiunta di eventuali layer aggiunti dall'utente
				var userWMSList = this.TOCPanel.getVisibleUserWMSList();
				for (var i=0; i< userWMSList.length; i++) {
					var idxObj = userWMSList[i]; 
					var currCat = this.TOCPanel.tocInfo.getCategoryInfo(idxObj.catTreeIdx);
					var currLayer =  currCat.layers[idxObj.layTreeIdx];
					if (currLayer.serverID) { 
					//var server = this.TOCPanel.tocInfo.getServer(currLayer.serverID);
					
						if (currLayer.queryable) {
							var currUrl = (currLayer.url) ? currLayer.url : this.paramsJS.getServer(currLayer.serverID, mappa).url;
							//var infoformat ="application/vnd.ogc.gml";
							
							var infoformat = "";
							var formats = currLayer.getFeatureInfoFormats;
							// Se abilitato GML cerca se c'e'
							if (this.paramsJS.comportamento.wmsUtente.usaGML) {
								
								for (var j=0; j < formats.length; j++ ) {
									var currFormat = formats[j];
									if (currFormat.indexOf("gml") != -1) {
										infoformat = currFormat;
										if (infoformat == "text/gml") {
											break;
										}
									}
								}
							}	
							// Se non disponibile formato gml o non abilitato sul portale tolomeo
							// si accontenta di un formato text con preferenza di text/html
							if (infoformat == "") {
								for (var j=0; j < formats.length; j++ ) {
									var currFormat = formats[j];
									if (currFormat.indexOf("text/") != -1) {
										infoformat = currFormat;
										if (infoformat == "text/html") {
											break;
										}
									}
								}	
							}
							// Se disponibile un formato aggiunge il layer alla lista di quelli interrogabili
							if (infoformat != "") {
								// Workaround per evitare che venga preso versione GML3
								// Andrebbe gestito meglio, rendendo anche la parte server in grado di gestire le versioni gml successive alla 2
								// nella classe GetFeatureInfoLayer del package sit
								if (infoformat.indexOf("application/vnd.ogc.gml") != -1) {
									infoformat = "application/vnd.ogc.gml";
								}
								var entry = {
										url: currUrl,
										wmsname: currLayer.name,
										codTPN: currLayer.codTPN,
										descrizione: currLayer.descr,
										infoformat: infoformat
									};
								queryableLayers.push(currLayer.codTPN);
								additionalWMSLayers.push(entry);	
							}
						}
					}
				}
				
				if ((queryableLayers.length == 0) && 
					 additionalWMSLayers.length == 0) {
					Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.onMappaSelect.title"),
							ToloI18n.getMsg("ToloMapAPIExt.onMappaSelect.msg"));
					this.ajaxQuerySelectOK(null);
					return;
				}			
				
				codTPN = queryableLayers.join(",");
				
				// Se si chiede di forzare la selezione su un certo codTPN si fa in modo di passare solo quello se presente fra i layer interrogabili
				/*
				if(codTpnToForceSelection){
					if(queryableLayers.length > 0 && codTPN.indexOf(codTpnToForceSelection) != -1){
						codTPN = codTpnToForceSelection;
						additionalWMSLayers.length = 0;
					} else if(additionalWMSLayers.length > 0 && additionalWMSLayers.join(",").indexOf(codTpnToForceSelection) != -1) {
						additionalWMSLayers = [];
						additionalWMSLayers[0] = codTpnToForceSelection;
						codTPN = "";
					}
				}
				*/
			} else {
				codTPN = this.paramsJS.getSelectableCodTPN().join(",");
			}
		} else {
			codTPN = this.getCurrentSelectLayer().codTPN;
		}
		
		var buff = codTPN.split(",");
		var stylesArr = new Array();
		for (var i=0; i<buff.length; i++) {
				var legendaInfo = this.paramsJS.getLegendaLayerInfoByCodTPN(buff[i], nmappa, (this.TOCPanel ? this.TOCPanel.tocInfo : null))			
				var stylebuff = (legendaInfo.tocInfoLayerInfo) ? legendaInfo.tocInfoLayerInfo.style : (legendaInfo.presetLayerInfo ? legendaInfo.presetLayerInfo.defaultStyle : "");  			
				stylesArr.push(stylebuff);
		}
		var styles = stylesArr.join(","); 
		
		// raggio di tolleranza 6 pixel
		var tolleranceRange = this.viewer.pluginGetResolution() * 6;
			
		var bounds = this.viewer.pluginGetMapExtent();
		
		// Chiamata Ajax per effettuare l'intersezione e ricevere l'oggetto selezionato
		var ajaxOptions = { method: 'post',
			url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxSpatialQueryServlet',
			params: {
				dtInizioFiltro: this.temporalFilterDtInizio,
				dtFineFiltro: this.temporalFilterDtFine,
				customQueryParams: Ext.JSON.encode(this.getCustomQueryParams()[nmappa]),
				coordX: point.x, 
				coordY: point.y,
				codTPN: codTPN,
				styles: styles,
				range: tolleranceRange,
				SRID: this.paramsJS.mappe.SRID,
				format: 'ext',
				selectionMode: selectionMode,
				//Parametri aggiunti per GetFeatureInfo
				bbox:  bounds.left+","+bounds.bottom+","+bounds.right+","+bounds.top ,
				mapwidth:  this.viewer.pluginGetMapWidth()  ,
				mapheight: this.viewer.pluginGetMapViewerHeight() ,
				X: mapXPixel,
				Y: mapYPixel,
				additionalWMSLayers: (additionalWMSLayers && additionalWMSLayers.length > 0) ? Ext.JSON.encode(additionalWMSLayers) : undefined,
				paramPreset: this.paramsJS.nomePreset
			},
			success: function(results, store){this.ajaxQuerySelectOK(results, store, addToSelected, visualize);},
			failure: function(transport){
				this.fireEvent('selectRequestEnd',{
					ok:false,
					nResults:0,
					errText:transport.responseText?transport.responseText:""+transport
				});
				this.showAjaxError(transport);
			}, 
			scope: this
		}
		
		// Aggiunta parametri WMS da url
		Ext.apply(ajaxOptions.params, this.paramsJS.urlAdditionalParams);
				
		if(this.fireEvent('selectRequestBeforeStart')){
			new TolomeoExt.ToloCrossAjax().request(ajaxOptions);
			this.fireEvent('selectRequestStart');
		}
		this.onBusy(true);
	},	

	/**
	 * Method: ajaxQuerySelectOK
	 * Funzione di callback per la chiamata ajax onMappaSelect {link #onMappaSelect} che identifica gli oggetti presenti in una certa posizione
	 *
	 * Parameters:
	 * results - {} il risultato della richiesta.
	 * store - {} lo store dei dati.
	 */
	ajaxQuerySelectOK: function (results, store, addToSelected, visualize) {
		
		if(results){		
			var geoms = new JSGeometryArray();
			geoms.FromStore(results, store);			
			
			if (geoms.geometries.length==0) {
				this.clearSelected();
			} else {
				this.addSelected(geoms, addToSelected, visualize);	
			}
		} 
		
		this.fireEvent('selectRequestEnd',{
			ok:true,
			nResults:results?geoms.geometries.length:0,
			errText:null
		});		
		
		this.onBusy(false);	
		
		//this.fireEvent('onObjectSelect', geoms);				
		/*
		var selLayer = this.getCurrentSelectLayer();
		if (selLayer.azioniEventiVis.autoVisOnSelect) {
			this.onIdentify();
		}
		*/
	
	    this.fireEvent('onOperationPressDefault', 2);
	},

	/**
	 * Method: showAjaxError
	 * Visualizza messaggio di errore in caso di errore Ajax
	 *
	 * Parameters:
	 * transport - {} transport, risposta della chiamata ajax.
	 * store - {} store.
	 */
	showAjaxError: function (transport) {
		this.onBusy(false);
		if(transport.responseText){
			alert(transport.responseText);
		}else{
			alert(transport);
		}
	},

	// sarebbero da gestire come metodi un oggetto mappa
	//TODO
	//Funzioni di busy

	/**
	 * Property: mapBusy
	 * {Number} 
	 */
	mapBusy: 0,
	
	/**
	 * Method: isBusy
	 * 
	 * Returns:
	 * {Boolean}
	 */
	isBusy: function () { return this.mapBusy != 0; },
	
	/**
	 * Method: onBusy
	 *
	 * Parameters:
	 * areYouBusy - {} areYouBusy.
	 */
	onBusy: function (areYouBusy){
		/* TODO
		if(areYouBusy){
			this.mapBusy++;
			this.refreshBusy();
			//if (this.myMask) this.myMask.show();
		}else{
			this.mapBusy--;
			if(!this.isBusy()){
				this.refreshBusy();
				//if (this.myMask) this.myMask.hide();
			}
		}
		*/
	},
		
	/**
	 * Method: noneBusy
	 * 
	 */
	noneBusy: function (){
		/* TODO
		this.mapBusy = 0;
		if (this.myMask) this.myMask.hide();
		*/
	},
	
	/**
	 * Method: refreshBusy
	 * 
	 */
	refreshBusy: function() {
		/* TODO
		if (this.myMask) 
		if (this.mapBusy) this.myMask.show();
		else this.myMask.hide();
		*/
	},
	
	/**
	 * Method: onScaleChange
	 * Chiamato dal plugin ogni volta che cambia il livello di zoom
	 */
	onScaleChange: function () {
		updateTocScale(this.viewer.pluginGetCurrentZoom());
		updateZoomToScale(this.viewer.pluginGetCurrentZoom());
	},

	/**
	 * Method: addHighlighted
	 * Sulla mappa e' possibile evidenziare degli oggetti. Questo e' utile, per esempio, nelle ricerche, per mostrare quale e' l'oggetto trovato.
	 * Questa funzione consente di evidenziare l'oggetto, di aggiornare di conseguenza la mappa e di fare le altre azioni necessarie.
	 * L'attuale implementazione prevede che un solo oggetto possa essere evidenziato, quindi ogni nuovo va a sostituirsi a quello eventualmente presente.
	 *
	 * Parameters:
	 * geoms - {JSGeometryArray o JSGeometry} oggetto da evidenziare se passato un JSGeometryArray viene utilizzato il primo.
	 * bMulti - {boolean} se non definito o false non è consentita la presenza di più di un oggetto, se True è consentita.
	 */
	addHighlighted: function addHighlighted(geoms, bMulti) {
		var geom;
		
		if (!bMulti) this.evidenziazioneCorrente.clear();
		
		this.evidenziazioneCorrente.add(geoms);
		
		//accendo il layer sul quale eseguo l'highlighted nel caso fosse spento in legenda...
		var codTPN = this.evidenziazioneCorrente.geometries[this.evidenziazioneCorrente.geometries.length-1].codTPN;
		if (codTPN && this.TOCPanel) {
			// se codTPN non è nullo e non è zero
			this.TOCPanel.setLayerVisibility(codTPN);
		}
		
		if (this.viewer!=null)
			this.viewer.pluginAddHighlighted(this.evidenziazioneCorrente, bMulti);
			
		/* Vecchia versione monooggetto
		if(geoms instanceof JSGeometryArray){
			this.evidenziazioneCorrente = geoms.geometries[0];
		}else if(geoms instanceof JSGeometry){
			this.evidenziazioneCorrente = geoms;
		}else{
			alert("tipo sconosciuto " + geoms);
			return;
		}
		
		if (this.viewer!=null)
			this.viewer.pluginAddHighlighted(this.evidenziazioneCorrente);*/
	},

	/**
	 * Method: clearHighLigthed
	 * Svuota la evidenziazione corrente, 
	 * deselezionando gli oggetti dalla mappa ed effettuando il resto delle operazioni necessarie (come l'aggiornamento delle operazioni di editing, interrogazione etc. possibili)
	 *
	 * Parameters:
	 * bRedraw - {boolean} Se non definito o false non è consentita la presenza di più di un oggetto, se True è consentita.
	 */
	clearHighLigthed: function (bRedraw) {
	
		this.evidenziazioneCorrente.clear();
		if (this.viewer.pluginClearHighlighted(bRedraw)) this.viewer.pluginRefreshMap();
		
		/* Vecchia versione monooggetto
		this.evidenziazioneCorrente = null;
		if (this.viewer.pluginClearHighlighted(bRedraw)) this.viewer.pluginRefreshMap();
		*/
	},

	/**
	 * Method: encodeToggleGroup
	 *
	 * Parameters:
	 * geoms - {JSGeometryArray o JSGeometry} Oggetto da evidenziare, se passato un JSGeometryArray viene utilizzato il primo.
	 */
	addAutoidentified: function (geoms) {
		if(geoms instanceof JSGeometryArray){
			this.autoIdentifyCorrente = geoms;
		}else if(geoms instanceof JSGeometry){
			this.autoIdentifyCorrente = geoms.add(geoms);
		}else{
			alert(ToloI18n.getMsg("ToloMapAPIExt.addAutoidentified.msg"));
			return;
		}
		this.viewer.pluginAddAutoidentified(this.autoIdentifyCorrente);
	},

	/**
	 * Method: clearAutoidentified
	 * Svuota la evidenziazione corrente, deselezionando gli oggetti dalla mappa ed effettuando il resto delle operazioni necessarie (come l'aggiornamento delle operazioni di editing, interrogazione etc. possibili)
	 *
	 * Parameters:
	 * bRedraw - {boolean} bRedraw
	 */
	clearAutoidentified: function (bRedraw) {
	
		this.autoIdentifyCorrente = null;
		if (this.viewer.pluginClearAutoidentified(bRedraw)) this.viewer.pluginRefreshMap();
	},

	/**
	 * Method: addSelected
	 * Sulla mappa e' possibile selezionare degli oggetti per sottoporli ad editing, interrogazione o altro. Le operazioni possibili sono controllate da configurazione.
	 * Questa funzione consente di selezionare l'oggetto, di aggiornare di conseguenza la mappa e di fare le altre azioni necessarie.
	 * L'attuale implementazione prevede che un solo oggetto possa essere evidenziato, quindi ogni nuovo va a sostituirsi a quello eventualmente presente.
	 *
	 * Parameters:
	 * geoms - {JSGeometryArray o JSGeometry} Oggetto da evidenziare, se passato un JSGeometryArray viene attivata una combobox sull'interfaccia grafica per permettere di scegliere.
	 *  bClearUrl - Indica se resettare l'eventuale pagina di identify 
	 * Quando la scelta è stata fatta viene chiamata la funzione onSelectedFromChoice()
	 */
	addSelected: function (geoms, addToSelected, visualize, bClearUrl) {
		
		var jsGeoArr;
		
		if(geoms instanceof JSGeometry){
			jsGeoArr = new JSGeometryArray();
			jsGeoArr.add(geoms); 
		}else{
			jsGeoArr = geoms;
		}
						
		if (jsGeoArr.geometries.length==1) {
			
			if(!addToSelected){
				this.clearSelected(false, undefined, bClearUrl);
			}else if (this.selezioneCorrente.ContainsCodTPN(jsGeoArr.geometries[0].codTPN)) {			
			// In ogni momento e' possibile che ci sia un solo oggetto selezionato per ogni codTPN
			// Questo vincolo e' stato messo per semplificare l'utilizzo
			// Verifica se già presente un oggetto dello stesso codTPN
				// lo cancella
				this.clearSelected(false, jsGeoArr.geometries[0].codTPN, bClearUrl);
			}
			
			//ALE1 selezioneCorrente = jsGeoArr.geometries[0];
			this.selezioneCorrente.add(jsGeoArr.geometries[0]);
			this.viewer.pluginAddSelected(jsGeoArr.geometries[0]);
			
			this.applyCustomQuery();
								
			if(this.paramsJS.isSelectable(jsGeoArr.geometries[0].codTPN)){
				this.setCurrentSelectLayer(jsGeoArr.geometries[0].codTPN);
			}
			this.fireEvent('onObjectSelect', geoms);
			
			var selLayer = this.getCurrentSelectLayer();
			if (selLayer && selLayer.azioniEventiVis && (selLayer.azioniEventiVis.autoVisOnSelect || visualize)) {
				this.onIdentify();
			}
			
		} else if (jsGeoArr.geometries.length>1) {
			
			var dataArray = [];
			
			var descrizioneLayer = null;
			var currentCodTPN = null;
			var z_index = 1000;
			for(var i=0; i<jsGeoArr.geometries.length;i++){
				var jsG = jsGeoArr.geometries[i];
				if(!currentCodTPN || currentCodTPN!=jsG.codTPN){
					descrizioneLayer = this.paramsJS.getParamJSLayer(jsG.codTPN).descrizioneLayer;
					z_index++;
				}
				dataArray.push([z_index+descrizioneLayer,jsG.codTPN,jsG.description,jsG]);
				currentCodTPN = jsG.codTPN;
			}
			
		    var store = Ext.create('Ext.data.ArrayStore',{
		    		fields: [
				       {name: 'z_index'},
				       {name: 'codTPN'},
				       {name: 'objectDescription'},
				       {name: 'jsGeometry'}
				    ], 
		            data: dataArray,
		            sorters:[{property: 'objectDescription', direction: "ASC"}],
		            groupField:'z_index'
		        });
		    
		    var listView = Ext.create('Ext.grid.Panel',{ 
		        store: store, 
		        features: [{ftype:'grouping', groupHeaderTpl: ['{name:this.formatName}',
														        {
														            formatName: function(name) {
														                return name.substr(4);
														            }
														        }]}],
		        emptyText: ToloI18n.getMsg("ToloMapAPIExt.addSelected.emptyText"),
		        startCollapsed : false, 
		      
		        columns: [		        	
		        	{text: ToloI18n.getMsg("ToloMapAPIExt.addSelected.desc"),dataIndex:'objectDescription',flex: 1, menuDisabled: true, sortable: false},
		        	{text: ToloI18n.getMsg("ToloMapAPIExt.addSelected.layer"),dataIndex:'layerDescription', hidden: true, menuDisabled: true, width:0}
		        	
		        ],
		        listeners: {
					itemmouseenter: {
						fn: function (dv, index, node, e) {
        					var record = dv.getRecord( node ).data;
        					this.onChangeFromChoice(record.jsGeometry);
        					return true;
        				},
        			  	scope: this
					},
					itemmouseleave: {
						fn: function (dv, index, node, e) {
							var record = dv.getRecord( node ).data;
							this.clearHighLigthed();
							return true;
						},
						scope: this
					},
					itemclick: {
						fn: function (dv, index, node, e) {
							var record = dv.getRecord( node ).data;
							var selected = record.jsGeometry;
							
							selected.relatedGeoms = jsGeoArr.getByCodTPN(selected.codTPN);
							this.onSelectedFromChoice(selected,addToSelected,visualize);
							return true;
						},
					  	scope: this
					}
				}
			});	    	
		    		    
			if(this.selectedChoiceWindow){
				this.selectedChoiceWindow.close();
			} 
			
			this.selectedChoiceWindow = Ext.create('Ext.Window', {
				title: ToloI18n.getMsg("ToloMapAPIExt.addSelected.win"),
				x: 50,
				width: 350,
				height: 300,
				layout:'fit',
				autoScroll: true,
				constrain: true,
				bodyStyle: 'background-color:white',
				items: [listView]
			}).show();
		}
	},
	
	/**
	 * Method: queryingById
	 * Fa un interrogazione ajax al server per recuperare la geometria dell'oggetto.
	 * Come parametri per l'interrogazione utilizza il codTPN e l'IDTPN ed accetta 
	 * come, parametri ulteriori, le funzioni da richiamare in caso di successo o di
	 * fallimento. Se IDTPN è un array verranno cercati tutti gli ID contenuti
	 *
	 * Parameters:
	 * codTPN - {String} codTPN
	 * IDTPN - {String or Array} IDTPN
	 * onSuccess - {Function} onSuccess
	 * onFailure - {Function} onFailure
	 * scope - {Object} contesto delle chiamate di callback
	 */
	queryingById: function(codTPN, IDTPN, onSuccess, onFailure, scope){
		/** {String} */
		var ids = "";
		if (IDTPN instanceof Array) {
			for (var i=0; i<IDTPN.length; i++) {
				ids += ((ids=="") ? "" : "||")  + IDTPN[i] ;
			}
		} else {
			ids=IDTPN;
		}
		
		var ajaxOptions = {
			url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxQueryByIDServlet',
			method: 'post',
			params: {
				codTPN: codTPN, 
				IDTPN: ids, 
				SRID: this.paramsJS.mappe.SRID, 
				format: 'ext',
				paramPreset: this.paramsJS.nomePreset
				},
			success: onSuccess,
			failure: onFailure || this.showAjaxError,
			scope: scope || this
		}

		// Aggiunta parametri WMS da url
		Ext.apply(ajaxOptions.params, this.paramsJS.urlAdditionalParams);
		
		new TolomeoExt.ToloCrossAjax().request(ajaxOptions);
	},
	
	/**
	 * Method: addSelectedByID
	 * Aggiunge a selected interrogando via ajax il layer per codTPN ed IDTPN 
	 *
	 * Parameters:
	 * codTPN - {String} codTPN
	 * IDTPN - {String or Array} IDTPN
	 * bClearUrl - Indica se resettare l'eventuale pagina di identify 
	 *
	 * Returns:
	 * {<JSGeometryArray>}
	 */
	addSelectedByID: function (codTPN, IDTPN, bClearUrl) {		
		this.queryingById(codTPN, IDTPN, function(res) { this.doAddSelectedByIDAjaxCallback(res, bClearUrl); }, this.doAddSelectedByIDAjaxFailure, this);
	},
	
	/**
	 * Method: zoomToSelected
	 * Esegue lo zoom ad una zona selezionata.
	 *
	 * Parameters:
	 * scale - {Number} zoom, se valorizzato viene fatto lo zoom alla data scala
	 * buffer - {Number} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	zoomToSelected: function(zoom, buffer) {
		this.viewer.pluginZoomToSelected(zoom, buffer);
	},
	
	/**
	 * Method: centerOnSelected
	 * Riposiziona la mappa mettendo al centro la feature selezionata e mantenendo la scala attuale.
	 */
	centerOnSelected: function(){
		var zoom = this.viewer.pluginGetCurrentZoom();
		this.zoomToSelected(zoom);
	},
	
	/**
	 * Method: zoomToHighlighted
	 * Esegue lo zoom ad una zona evidenziata.
	 * 
	 * Parameters:
	 * zoom - {Number} il valore di zoom.
	 * buffer - {Integer} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	zoomToHighlighted: function(zoom, buffer) {
		this.viewer.pluginZoomToHighlighted(zoom, buffer);
	},
	
	/**
	 * Method: centerOnHighlighted
	 * Riposiziona la mappa mettendo al centro la feature evidenziata e mantenendo la scala attuale.
	 */
	centerOnHighlighted: function(){
		var zoom = this.viewer.pluginGetCurrentZoom();
		this.zoomToHighlighted(zoom);
	},
	
	/**
	 * Method: zoomToAutoidentified
	 *
	 * Parameters:
	 * zoom - {Number} il valore di zoom.
	 */
	zoomToAutoidentified: function(zoom) {
		this.viewer.pluginZoomToAutoidentified(zoom);
	},	
	
	/**
	 * Method: zoomToExtent
	 * Esegue lo zoom alla massima estenzione della mappa.
	 * 
	 * Parameters:
	 * geometry - {Mixed} Stringa wkt della geometria o oggetto di tipo BBox
	 * buffer - {Number} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	zoomToExtent: function(geometry, buffer) {
		this.viewer.pluginZoomToExtent(geometry, buffer);
	},	
	
	/**
	 * Method: zoomToScale
	 * esegue lo zoom ad una specifica scala.
	 * 
	 * Parameters:
	 * scale - {Number} il valore di scala.
	 */
	zoomToScale: function (scale){
		this.viewer.pluginZoomToScale(scale);
	},
	
	/**
	 * Method: zoomToObj
	 * Esegue uno zoom all'oggetto dopo aver interrogato il server per recuperare la geometria
	 * per mezzo di codTPN e IDTPN.
	 * Se il parametro selectIt è impostato a true l'oggetto viene selezionato, se = false viene evidenziato 
	 * Se bMulti == true e selectIt==false viene abilitata l'evidenziazione multipla (l'oggetto viene evidenziato insieme agli altri eventualmente già evidenziati) 
	 *
	 * Parameters:
	 * codTPN - {String} codice del layer
	 * IDTPN - {String o Array} id della feature
	 * selectIt - {Boolean} se true viene selezionato
	 * scale - {Integer} scala, se valorizzato viene fatto lo zoom alla data scala
	 * buffer - {Integer} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	zoomToObj: function(codTPN, IDTPN, selectIt, scale, buffer) {
		var onSuccess = function(res) { this.doZoomToObjAjaxCallback(res, selectIt, scale, buffer); };
		this.queryingById(codTPN, IDTPN, onSuccess, this.showAjaxError);	
	},

	/**
	 * Method: doZoomToObjAjaxCallback
	 * Funzione di callback della chiamata Ajax che effettua la zoomToObj
	 *
	 * Parameters:
	 * res - {} risposta della chiamata ajax
	 * selectIt - {Boolean} se true viene selezionato
	 * scale - {Integer} scala, se valorizzato viene fatto lo zoom alla data scala
	 * buffer - {Integer} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	doZoomToObjAjaxCallback: function(res, selectIt, scale, buffer) {
		var geoms = new JSGeometryArray();
		geoms.FromUntypedArray(res[0].data);
		
		if (geoms.geometries.length>0) {
			if(selectIt && this.paramsJS.isSelectable(geoms.geometries[0].codTPN)) {
				this.clearSelected();			
				this.addSelected(geoms);
				this.zoomToSelected(scale, buffer);
			} else {
				this.clearHighLigthed();
				this.addHighlighted(geoms);
				this.zoomToHighlighted(scale, buffer);
			}
		}
	},
	
	/**
	 * Method: doAddSelectedByIDAjaxCallback
	 * Funzione di callback della chiamata Ajax che effettua la addSelectedByID 
	 *
	 * Parameters:
	 * res - {} risposta della chiamata ajax
	 *  bClearUrl - Indica se resettare l'eventuale pagina di identify 
	 */
	doAddSelectedByIDAjaxCallback: function (res, bClearUrl) {
		//var geoms = new JSGeometryArray(transport.responseText);
		var geoms = new JSGeometryArray();
		geoms.FromUntypedArray(res[0].data);
		 
		this.addSelected(geoms, undefined, undefined, bClearUrl);
	},

	/**
	 * Method: doAddSelectedByIDAjaxFailure
	 * Funzione di gestione errore avvenuto nella chiamata Ajax che effettua la ricerca
	 *
	 * Parameters:
	 * transport - {} risposta della chiamata ajax
	 */
	doAddSelectedByIDAjaxFailure: function (transport) {
		//TODO CrossAjax riadattare
		showAjaxError(transport);
	},

	/**
	 * Method: clearSelected
	 * Svuota la selezione corrente, deselezionando gli oggetti dalla mappa ed effettuando il resto delle operazioni necessarie (come l'aggiornamento delle operazioni di editing, interrogazione etc. possibili)
	 * Nel caso che sia definito codTPN l'operazione viene fatta solo sugli oggetti del layer corrispondente
	 *
	 * Parameters:
	 * bRedraw - {Boolean} bRedraw
	 * codTPN - {Integer} codTPN
	 *  bClearUrl - Indica se resettare l'eventuale pagina di identify 
	 */
	clearSelected: function (bRedraw, codTPN, bClearUrl) {
		var doit = this.fireEvent('onBeforeClearSelected', bRedraw, codTPN, bClearUrl);
		if (doit) {
			var removed = this.selezioneCorrente.clear(codTPN);
			if (bClearUrl==undefined || bClearUrl==null) bClearUrl = true; 

			// Elimina eventuale pagina di identify
			if (window.pannello && bClearUrl) this.clearURL ("pannello", "GET");		
			
			if (bRedraw) this.applyCustomQuery();
			if (this.viewer.pluginClearSelected(bRedraw, codTPN)) this.viewer.pluginRefreshMap();
			// Modifica di conseguenza le operazioni possibili (icone)
			//TODO
			this.togglePermittedOperations();
			
			this.fireEvent('onAfterClearSelected', bRedraw, codTPN, bClearUrl);
			
			return removed;	
		} else {
			return [];
		}
		
	},

	/**
	 * Method: refreshSelected
	 * Aggiorna la selezione rileggendo dal layer la geometria attualmente selezionata
	 */
	refreshSelected: function () {
		if (this.selezioneCorrente.size()!=0) {
			
			var buff = new Array();
			for (var i=0;i<this.selezioneCorrente.geometries.length;i++) {
				var elem = new Object();
				elem.codTPN = this.selezioneCorrente.geometries[i].codTPN;
				elem.key = this.selezioneCorrente.geometries[i].key;
				buff.push(elem);
			}
			
			this.clearSelected(undefined, undefined, false);
			for (var i=0;i<buff.length;i++) {
				this.addSelectedByID(buff[i].codTPN, buff[i].key, false);
			}
		}
		
	},
	
//	/**
//	 * Method: zoomToExtent
//	 * Visualizza sulla mappa l'intero extent passato 
//	 *
//	 * Parameters:
//	 * geometryWKT - {} rappresentazione WKT della geometria da inquadrare
//	 */
//	zoomToExtent: function (geometryWKT){
//		this.viewer.pluginZoomToExtent(geometryWKT);
//	},
		
	/**
	 * Method: addMarker 
	 * Aggiunge un marker alla  mappa.
	 * 
	 * Parameters:
	 * x - {Integer} x
	 * y - {Integer} y
	 */
	addMarker: function(x,y) {
		this.viewer.pluginAddMarker(x,y);
	},
	
	/**
	 * Method: setMarker 
	 * Imposta un marker sulla  mappa, cancellando markers esistenti
	 * 
	 * Parameters:
	 * x - {Integer} x
	 * y - {Integer} y
	 */
	setMarker: function(x,y) {
		this.viewer.pluginAddMarker(x,y,null,true);
	},
	
	/**
	 * Method: clearMarkers
	 * Rimuove un marker dalla mappa.
	 *
	 * Parameters:
	 * x - {Integer} x
	 * y - {Integer} y
	 */
	clearMarkers: function(x,y) {
		this.viewer.pluginClearMarkers();
	},
	
	/**
	 * Method: addPopup 
	 * Aggiunge un popup alla  mappa.
	 * 
	 * Parameters:
	 * x - {Integer} x
	 * y - {Integer} y
	 * htmlText - {String} testo html
	 * isUnique - {boolean} se deve essere l'unico popup presente
	 */
	addPopup: function(x,y,htmlText,isUnique,editable) {		
		this.viewer.pluginAddPopup(x,y,htmlText,isUnique,editable);
	},	

	/**
	 * Method: updateImplicitCustomQuery
	 *  
	 */
	updateImplicitCustomQuery: function (){
	
		this.implicitCustomQuery = new Object();
		
		// Aggiunta SelectCustomQuery
		for(var index=0; index<this.paramsJS.azioniEventi.eventiLayerList.length; index++) {
			var paramJSLayer = this.paramsJS.azioniEventi.eventiLayerList[index];
		
			if (((paramJSLayer.customQueryOnSelect) && (paramJSLayer.customQueryOnSelect!='')) || 
				((paramJSLayer.customQueryOnNOSelect) && (paramJSLayer.customQueryOnNOSelect!=''))){
				var sel = this.selezioneCorrente.getByCodTPN(paramJSLayer.codTPN)
				var codTPN = paramJSLayer.codTPN;
				var buffCodTPN = codTPN + '';
				buffCodTPN = buffCodTPN.replace("-","M");
				var nome = "CQSELCOD" + buffCodTPN;	
				// ReplaceAll %SELCOD%
				 
				var valore = null;			
				
				if (sel) {
					// ci sono oggetti selezionati per questo layer
					valore = paramJSLayer.customQueryOnSelect;	
					var RE = new RegExp("%SELCOD%", "ig");
					valore = valore.replace(RE, codTPN);
					
					// ReplaceAll 
					var RE = new RegExp("%SELID%", "ig");
					valore = valore.replace(RE, sel.geometries[0].key);
					
				} else {
					// Non ci sono oggetti selezionati per questo layer
					valore = paramJSLayer.customQueryOnNOSelect;
				}
				
				eval ("this.implicitCustomQuery."+nome+"=valore");
			}            	
		}
		
		this.implicitCustomQuery.CQTEMPORALFILTERDTINIZIO = this.temporalFilterDtInizio; 
		this.implicitCustomQuery.CQTEMPORALFILTERDTFINE = this.temporalFilterDtFine;
		// WMS-TIME
		var dInizioBuff = Ext.Date.parse(this.temporalFilterDtInizio,"d/m/Y");
		var dFineBuff = Ext.Date.parse(this.temporalFilterDtFine,"d/m/Y");
		var format = "Y-m-d\\TH:i:s\\Z";
		this.implicitCustomQuery.TIME = Ext.Date.format(dInizioBuff, format) + "/" + Ext.Date.format(dFineBuff, format) ; 
	},
	
	/**
	 * Method: applyCustomQuery
	 * Consente di utilizzare una query personale.
	 * 
	 */
	applyCustomQuery: function (){
	
		var params = this.getCustomQueryParams();
	
		if ( !this.paramsPrev || (Ext.JSON.encode(params)!= Ext.JSON.encode(this.paramsPrev))) {
			this.viewer.pluginUpdateCustomQuery(params);
			if (this.TOCPanel!=null){
				this.TOCPanel.updateCustomQuery(params);
			}
		}
		
		this.paramsPrev=params;
		
	},
		
	/**
	 * Method: getCustomQueryParams
	 * 
	 */
	getCustomQueryParams: function () {
	
		var params = new Array();
	
		this.updateImplicitCustomQuery();
		
		for (var i = 0; i<this.paramsJS.mappe.mappaList.length; i++) {
			
			var mappa = this.paramsJS.mappe.mappaList[i];
		
			var customQueryParams = new Object();
		    for (var j=0;j<mappa.customQueryList.length ;j++) {
		    	eval ("customQueryParams."+mappa.customQueryList[j].nome+"='"+mappa.customQueryList[j].query+"';");
		   	}
		   	
		    customQueryParams = Ext.apply(customQueryParams,this.implicitCustomQuery );
		    customQueryParams = Ext.apply(customQueryParams,this.explicitCustomQueryParams );
		   	params.push(customQueryParams);        
		
		}
		
		return params;
		
	},
	
	
	
	addExplicitCustomQueryParam: function(customQueryobj) {
		Ext.apply(this.explicitCustomQueryParams, customQueryobj );
		this.applyCustomQuery();
	},
	
	removeExplicitCustomQueryParam: function(name) {
		this.explicitCustomQueryParams[name] = undefined;
		this.applyCustomQuery();
	}, 
	
	getExplicitCustomQueryParam: function(name) {
		return this.explicitCustomQueryParams[name];
	},

	/**
	 * Method: gotoPosition 
	 *
	 * Parameters:
	 * coordX - {Integer} coordinata X.
	 * coordY -{Integer} coordinata Y.
	 * zoomFactor - {} livello di zoom.
	 * withMarker - {} withMarker.
	 * crsCode - {String} codice EPSG del sitema di riferimento in cui sono le coordinate passate.
	 */
	gotoPosition: function (coordX, coordY, zoomFactor, withMarker, crsCode) {
		
		zoomFactor = zoomFactor || this.viewer.pluginGetCurrentZoom();
		var currPoint = new Point(coordX,coordY);
		
		// Se è stato passato un sistema di riferimento fra qelli gestiti e diverso da quello attuale
		// riproietto le coordinate
		if(crsCode && this.projectionCrs[crsCode]){
			var currSrsCode = this.getProjectionCode();
			if(currSrsCode != crsCode){
				var currProj = new TolomeoExt.Projection(currSrsCode);
				var sourceProj = new TolomeoExt.Projection(crsCode);		
				currPoint = TolomeoExt.Projection.transform(currPoint,sourceProj,currProj);
			}		
		}				
		this.viewer.pluginGotoPosition(currPoint.x, currPoint.y, zoomFactor, withMarker, this.TOLOMEOServer + this.TOLOMEOStaticRoot + '/img/markers/arrow_Marker.png'); 
	},
	
	/**
	 * Method: doOpenActionsJS
	 * 
	 */
	doOpenActionsJS: function() {
		if (this.openActionsJS!=null) {
			this.openActionsJS();
		} 
		
		var bOnOpenDrawMap = false;
		var bUnComando = false;
		var buff;
		
		var queryString = window.location.toString();
		var pos = queryString.indexOf('?')
		if (pos!=-1) {
			queryString = queryString.substr(pos);
			var qsObj = Ext.Object.fromQueryString(queryString);
			if (qsObj[this._getPermalinkParameterName("cmdUrl")] || qsObj[this._getPermalinkParameterName("cmdUrlComp")]) {
				bUnComando = true;
				pro = Ext.create('TolomeoExt.ToloProcedure', {
			    			cmdUrl: qsObj[this._getPermalinkParameterName("cmdUrl")],
			    			cmdUrlComp: qsObj[this._getPermalinkParameterName("cmdUrlComp")]
			    		});
			    		
			    buff = 	pro.run(this);	
			    bOnOpenDrawMap = bOnOpenDrawMap || buff;
			} 
			
			// Popups.
			// Fare prima di posizionamento perchè openalyers sembra spostare la mappa quando si aggiugono popup 
			var popupPrm = qsObj[this._getPermalinkParameterName("popup")];
			if (popupPrm) {
				bUnComando = true;
				var conf = [];
				if (popupPrm instanceof Array) {
					for (var i=0; i<popupPrm.length ; i++) {
						var arg = popupPrm[i].split("|"); 
						conf.push({x: arg[0], y: arg[1], t: arg[2], e: arg[3]});
					}
				} else {
					var arg = popupPrm.split("|"); 
					conf.push({x: arg[0], y: arg[1], t: arg[2], e: arg[3]});
				}
				
				var popUpCommand = Ext.create('TolomeoExt.ToloCommand.addPopups', { conf: conf });
				buff = popUpCommand.run(this);
				bOnOpenDrawMap = bOnOpenDrawMap || buff; 
			}
			
			// Posizonamento per extent
			var ztePrmLeft   = qsObj[this._getPermalinkParameterName("left")];
			var ztePrmBottom = qsObj[this._getPermalinkParameterName("bottom")];
			var ztePrmRight  = qsObj[this._getPermalinkParameterName("right")];
			var ztePrmTop    = qsObj[this._getPermalinkParameterName("top")];
				
			if (ztePrmLeft && ztePrmBottom && ztePrmRight && ztePrmTop) {
				bUnComando = true;
				var zoomToCommand = Ext.create('TolomeoExt.ToloCommand.zoomToExtent', { left: ztePrmLeft, bottom: ztePrmBottom, right: ztePrmRight, top: ztePrmTop });
				buff = zoomToCommand.run(this);
				bOnOpenDrawMap = bOnOpenDrawMap || buff;
			}
			
			// Positionamento per centro e scala
			var ztsPrmX     = qsObj[this._getPermalinkParameterName("x")];
			var ztsPrmY     = qsObj[this._getPermalinkParameterName("y")];
			var ztsPrmScale = qsObj[this._getPermalinkParameterName("scale")];			
			
			if (ztsPrmX && ztsPrmY && ztsPrmScale) {
				bUnComando = true;
				var zoomToCommand = Ext.create('TolomeoExt.ToloCommand.zoomTo', { x: ztsPrmX, y: ztsPrmY, s: ztsPrmScale });
				buff = zoomToCommand.run(this);
				bOnOpenDrawMap = bOnOpenDrawMap || buff;
			}
			
			// Simulazione identify
			var iPrmX    = qsObj[this._getPermalinkParameterName("ix")];
			var iPrmY    = qsObj[this._getPermalinkParameterName("iy")];
			var iPrmSrid = qsObj[this._getPermalinkParameterName("isrid")];
			var iPrmLn   = qsObj[this._getPermalinkParameterName("iln")];
			
			if (iPrmX && iPrmY && iPrmSrid) {
				bUnComando = true;
				var identifyCommand = Ext.create('TolomeoExt.ToloCommand.identify', { x: Number(iPrmX.replace(",",".")), y: Number(iPrmY.replace(",",".")), srid: iPrmSrid, layerName: iPrmLn });
				buff = identifyCommand.run(this);
				bOnOpenDrawMap = bOnOpenDrawMap || buff;
			}
			
			// Note all'avvio
			var startPopup = qsObj[this._getPermalinkParameterName("startPopup")];
			if (startPopup) {
				var spp = Ext.create('TolomeoExt.ToloCommand.startPopup', 
						{ msg: startPopup});
				buff = spp.run(this);
				bOnOpenDrawMap = bOnOpenDrawMap || buff;
			}
			
			this.viewer.bOnOpenDrawMap = this.viewer.bOnOpenDrawMap || bOnOpenDrawMap || !bUnComando;			
		}
		
	},	

	/**
	 * Method: doOpenActions
	 * Esegue le azioni di apertura definite nel file .xml, come il posizionamento etc
	 */
	doOpenActions: function (){

		var action = this.paramsJS.azioniApertura.action;
	   	
	   	if (action == "ZoomTo") {      
	   		this.viewer.pluginGotoPosition (this.paramsJS.azioniApertura.coordX, this.paramsJS.azioniApertura.coordY, this.paramsJS.azioniApertura.zoom, this.paramsJS.azioniApertura.withMarker);      
		} else if (action == "ZoomToOgg")  {
			if(this.paramsJS.azioniApertura.zoomToCodTPN && this.paramsJS.azioniApertura.zoomToIdTPN){				
				this.zoomToObj(this.paramsJS.azioniApertura.zoomToCodTPN, this.paramsJS.azioniApertura.zoomToIdTPN, true);
			}			
				
			/* CODICE CHE NON SEMBRA PIU FUNZIONARE, SE VERIFICATO CHE NON UTILIZZATO, TOGLIERE
			if ((this.paramsJS.azioniApertura.zoomToJSGeometry!=null) & (this.paramsJS.azioniApertura.zoomToJSGeometry!="")) {
				var geoms = new JSGeometryArray();
				
				geoms.FromUntypedArray(this.paramsJS.azioniApertura.zoomToJSGeometry);
				if ((geoms.geometries.length==1) && (geoms.geometries[0].geometry!="")) {
				
					if (this.paramsJS.azioniApertura.modoEditingSingolo != null && 
						this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!=null &&
						this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!="") {
							// Se c'è modoEditingSingolo allora uso highlight perchè selected viene usato da editing singolo
							addHighlighted(geoms);
							if (geoms.geometries[0].isPoint()) {
								this.zoomToHighlighted(this.paramsJS.azioniApertura.zoom);
							} else {
								this.zoomToHighlighted();
							}	
					} else {
						
						// Se non c'è modoEditingSingolo allora uso selected, almeno le azioni sono subito disponibili
						this.addSelected(geoms);
						if (geoms.geometries[0].isPoint()) {
							this.viewer.pluginZoomToSelected(this.paramsJS.azioniApertura.zoom);
						} else {
							this.viewer.pluginZoomToSelected();
						}
					}
					
				}								
			}
			*/
		}
		
		if (this.paramsJS.azioniApertura.urlPannello) {
			var method = (this.paramsJS.azioniApertura.method || 'POST').toUpperCase();
			var m = this;
			setTimeout(function(){m.openURL(m.paramsJS.azioniApertura.urlPannello, "pannello", method)},500);
			/*			
			var method = (this.paramsJS.azioniApertura.method || 'POST').toUpperCase();
			this.openURL(this.paramsJS.azioniApertura.urlPannello, "pannello", method);
			*/
		}
		
		// Modo editing singolo. 
		// Se già presente seleziona e zoomToSelected all'oggetto da modificare,
		// altrimenti nulla 
		if (this.paramsJS.azioniApertura.modoEditingSingolo != null && 
			this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!=null &&
			this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!="") {
			//if (this.paramsJS.azioniApertura.modoEditingSingolo.conInsert==false) {
				//params.getAzioniApertura().getModoEditingSingolo().setEditingJSGeometry
				var geoms = new JSGeometryArray();
			
				geoms.FromUntypedArray(this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry);
				if ((geoms.geometries.length==1) && (geoms.geometries[0].geometry!="")) {
					this.addSelected(geoms);
					if (geoms.geometries[0].isPoint()) {
						this.zoomToSelected(this.paramsJS.azioniApertura.zoom);
					} else {
						this.zoomToSelected();
					}
				}
				
			//}
		}
	},
	
	cleanJSONQuotesOnKeys: function (json) {
    	return json.replace(/"(\w+)"\s*:/g, '$1:');
	},
	
	generatePermalink: function(startPopupText) {
		
		var proc = Ext.create('TolomeoExt.ToloProcedure', {});
		
		if(this.TOCPanel){
			var pl = this.TOCPanel.saveToCommand();
			proc.addCommand(pl);
		}

		// Popups
		// Fare prima di posizionamento
		var conf = [];
		var popups = this.viewer.pluginGetOpenedPopups();
		for (var i=0; i < popups.length; i++) {
			var p = popups[i];
			conf.push({x: p.lonlat.lon , y: p.lonlat.lat, t: p.contentHTML, e: p.editable});
		}
		var zt = Ext.create('TolomeoExt.ToloCommand.addPopups', 
							{ conf:conf	});
		proc.addCommand(zt);
		
		if (startPopupText) {
			var spp = Ext.create('TolomeoExt.ToloCommand.startPopup', 
					{ msg: startPopupText});
			proc.addCommand(spp);	
		}
		
		/* La posizione viene aggiunta in chiaro su richiesta di RT
		var zt = Ext.create('TolomeoExt.ToloCommand.zoomTo', {
								x:this.viewer.pluginGetCurrentX(),
								y:this.viewer.pluginGetCurrentY(),
								s: this.viewer.pluginGetCurrentZoom()});
		proc.addCommand(zt);
		*/

		var cmdParamNoQuotes=Ext.JSON.encode(proc); //this.cleanJSONQuotesOnKeys(Ext.JSON.encode(proc));
		//var cmdParamNoQuotesComp = LZString.compressToBase64(cmdParamNoQuotes); 
		
		//var msg =  "Lunghezza originale: " + encodeURIComponent(cmdParamNoQuotes).length;
		//msg += "<br/>" + "Lunghezza compressa:" + cmdParamNoQuotesComp.length;
		//msg += "<br/>";
		
		var pos = window.location.href.indexOf("?");
		var qs = {};
		if (pos!=-1) {
			qs = Ext.Object.fromQueryString(window.location.href.substring(pos));
		}
		qs[this._getPermalinkParameterName("cmdUrlComp")] = LZString.compressToBase64(cmdParamNoQuotes);
		
		qs[this._getPermalinkParameterName("x")] = this.viewer.pluginGetCurrentX();
		qs[this._getPermalinkParameterName("y")] = this.viewer.pluginGetCurrentY();
		qs[this._getPermalinkParameterName("scale")] = this.viewer.pluginGetCurrentZoom();

		//var proc1 = Ext.create('TolomeoExt.ToloProcedure', {});
		//proc1.addCommand(zt);
		//qs.cmdUrl=this.cleanJSONQuotesOnKeys(Ext.JSON.encode(proc1));
		
		var qs1 = window.location.protocol + "//" + window.location.host + window.location.pathname;
		
		qs1=Ext.String.urlAppend(qs1, Ext.Object.toQueryString(qs));
		
		return qs1;
		
	},
	
	
	showPermalink: function() {
		
		var permalink = this.generatePermalink();
		
		//window.location.href + ((window.location.href.indexOf("?")==-1) ? "?" : "&")  + "cmdUrlComp=" + LZString.compressToBase64(cmdParamNoQuotes) + '
		//var msg = '<a target="_blank" href="' + permalink +'">Permalink</a>';

		//Ext.MessageBox.show({title: "Permalink",  msg: msg });
		var thisid = this.apiid;
		var me = this;
		
		Ext.create('TolomeoExt.Window', {
		    title: ToloI18n.getMsg("ToloMapAPIExt.showPermalink.title"),
		    iconCls: 'iconPermalink',
		    modal: true,
		    height: 200,
		    width: 400,
		    layout: 'fit',
		    //cls: 'clearCSS',
		    items: { 
		        xtype     : 'textareafield',
		        grow      : false,
		        name      : 'permalink',
		        fieldLabel: '',
		        id : thisid + '-permalinkTextArea',
		        anchor    : '100%',
		        value : permalink,
		        selectOnFocus: true
		    },
		    dockedItems: [{
		        xtype: 'toolbar',
		        dock: 'bottom',
		        items: ['->','-',{
		        	iconCls: 'iconOpenInNewWin',
		            text: ToloI18n.getMsg("ToloMapAPIExt.showPermalink.nuovafin"),
		            listeners : {
			        	click : {
			        		fn :  function(){
			        					var permalinkTextAreaCmp = Ext.getCmp(thisid + '-permalinkTextArea');
					        			window.open(permalinkTextAreaCmp.getValue(),"_blank");
			        		}
			        	}
			        }
		        },{
		        	iconCls: 'iconOpenInNewWin',
		            text: ToloI18n.getMsg("ToloMapAPIExt.showPermalink.nota"),
		            listeners : {
			        	click : {
			        		fn :  function(){
			        			
			        			var permalinkTextAreaCmp = Ext.getCmp(thisid + '-permalinkTextArea');
			        			
			        			Ext.create('Ext.Window', {
			        				cls: 'clearCSS',
			        				modal:true,
			        				layout: 'fit',
			        				items:[{
			        			    	xtype: 'htmleditor',
			        			    	id: thisid + '-htmleditor',
			        			    	cls: 'clearCSS',
			        			    	enableAlignments: false,
			        			    	enableFont: false,
			        			    	enableLinks: true,
			        			    	enableSourceEdit: false,
			        			    	value: !permalinkTextAreaCmp.startPopup ? '' : permalinkTextAreaCmp.startPopup,
			        			    	listeners: {
			        			    		change: function(htlmcontrol, newval, oldval, eopts) {
			        		    				Ext.getCmp(thisid + '-btnOkInsNotaApertura').setDisabled(newval=="");
			        			    		}
			        			    	}
			        				}],
			        				buttons: [
			        			          { text: ToloI18n.getMsg("ToloMapAPIExt.showPermalink.btnOK"),
			        			        	disabled: true,
			        			        	id: thisid + '-btnOkInsNotaApertura',
			        			        	listeners: {
			        			        		click: function() {
			        			        			// setto nuovo valore
			        			        			var htmlEditorCmp = Ext.getCmp(thisid + '-htmleditor');
			        			        			var text = htmlEditorCmp.getValue();
			        			        			var pml = me.generatePermalink(text);
			        			        			
			        			        			// setto nuovo valore
			        			        			permalinkTextAreaCmp.setValue(pml);
			        			        			permalinkTextAreaCmp.startPopup = text;
			        			        			Ext.defer(function(){
			        			        				permalinkTextAreaCmp.focus();
			        			        			},200);
			        			        			this.up('.window').close();
			        				        	}
			        				         }
			        			          }
			        			    ],
			        			    listeners : {
			        			    	show : {
			        		        		fn :  function(){
				        		        			Ext.defer(function(){
				        		        				this.items.getByKey(thisid + '-htmleditor').focus();
			        			        			},200, this);
			        		        			
			        		        		}
			        		        	}
			        		        }
			        			}).show();
			        			
			        			/////////////////////////
			        			//window.open(permalink,"_blank");
			        		}
			        	}
			        }
		        }]
		    }],
		    listeners : {
	        	show : {
	        		fn :  function(){		        			
	        			this.items.getByKey(thisid + '-permalinkTextArea').focus();
	        		}
	        	}
	        }
		}).show();
						
	},
	
	exportForQgis : function(catIdx, layIdx, version){
		
		if(!this.TOCPanel) return;				
		
		this.exportForm.getForm().setValues({
			tocInfo: this.TOCPanel.tocInfo.JSONEncodeInfo(catIdx, layIdx),
			paramsJS: Ext.JSON.encode(this.paramsJS),
			nMappa: '0',
			idxCategoriaBase: catIdx,
			idxLayerBase: layIdx,
			version: version
		});
		
		this.exportForm.submit({
			url: this.TOLOMEOServer + this.TOLOMEOContext + '/ExportToQgisServlet',
			method: 'POST',
			target: '_blank'
		});
	},
	
	/**
	 * Method: onDigitizeEndGeometry
	 * Funzione chiamata alla fine del processo di digitalizzazione. 
	 * Viene invocata dalle funzioni piu' specifiche onDigitizeEndPolygon, onDigitizeEndPoint etc.
	 *
	 * Parameters:
	 * geometry - {JSGeometry} la geometria.
	 */
	onDigitizeEndGeometry: function (geometry){

		var	layer = this.getCurrentSelectLayer();
		
		// Se editing singolo ed è definita una geometria editing singolo 
		// (come nel caso di geometrie esistenti da modificare o delle quali inserire la geometria)
		// allora utilizzo la geometria esistente e modifico il solo campo geometria
		if ((this.paramsJS.azioniApertura.modoEditingSingolo!=null) && (this.paramsJS.azioniApertura.modoEditingSingolo!="") &&
			(this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!= null) && (this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!="")) {
			var geoms = new JSGeometryArray();
			geoms.FromUntypedArray(this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry);
			var geom1 = geoms.geometries[0];
			geom1.geometry = geometry.geometry;
			geometry = geom1;
			geometry.SRID = this.paramsJS.mappe.SRID;
			if (this.currentDigitizeOperation==this.digitizeOperationInsert) {
				this.geoOpToPostVar(this.operationGeometryModify);	
			} else {
				this.geoOpToPostVar(this.currentDigitizeOperation);
			}
		} else {
			geometry.codTPN = layer.codTPN;
			geometry.SRID = this.paramsJS.mappe.SRID;
			this.geoOpToPostVar(this.currentDigitizeOperation);
		}
		this.geometryToPostVar (geometry);
		switch (this.currentDigitizeOperation) {
	   		case this.digitizeOperationInsert:
	   			this.onDigitizeEndInsert(geometry);
	   			if ((this.paramsJS.azioniApertura.modoEditingSingolo!=null) && (this.paramsJS.azioniApertura.modoEditingSingolo!="") &&
					(this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!= null) && (this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!="")) {
	   				this.addSelectedByID(this.paramsJS.azioniApertura.modoEditingSingolo.layerCODTPN, this.paramsJS.azioniApertura.modoEditingSingolo.valoreChiave);
				} 
	   			break;
	   		case this.digitizeOperationSubtract:
	   			this.onDigitizeEndSubtract(geometry);
	   			//refreshSelected();
	   			break;
	   		case this.digitizeOperationAdd:
	   			this.onDigitizeEndAdd(geometry);
	   			//refreshSelected();
	   			break;
	   		case this.digitizeOperationAddSub:
	   			this.onDigitizeEndAddSub(geometry);
	   			//refreshSelected();
	   			break;
	   		case this.digitizeOperationVertexEdit:
	   			this.digitizeEndVertexEdit(geometry);
	   			//refreshSelected();
	   			break;
	   		case this.digitizeOperationDragDrop:
	   			this.digitizeEndDragDrop(geometry);
	   			//refreshSelected();
	   			break;
	   		default: alert (ToloI18n.getMsg("ToloButtonPanelExt.mnuGuida.text", {currentDigitizeOperation: currentDigitizeOperation}));

	   	}

		this.currentDigitizeOperation = '';
		
		var me = this;
		
		// ritardata perche' sennò avviene il cambio quando l'evento click non e' ancora stato consumato
		// e lo strumento di selezione esegue una selezione non voluta
		setTimeout(function(){
			me.fireEvent('onOperationPressDefault', 2);				                 
        }, 500);
	    
		this.fireEvent("digitizeEnd", geometry);
	},	

	/**
	 * Method: onDigitizeEndInsert
	 * Funzione chiamata alla fine del processo di digitalizzazione nel caso che l'operazione sia un inserimento. Viene invocata dalla funzione più generale onDigitizeEndGeometry etc.
	 * Si occupa di chiedere conferma ed eventualmente eseguire le azioni richieste invocando la doEventActions
	 *
	 * Parameters:
	 * geometry - {JSGeometry} la geometria.
	 */
	onDigitizeEndInsert: function (geometry){

		
		var layer = this.getCurrentSelectLayer();	
		var messint = ToloI18n.getMsg("ToloMapAPIExt.onDigitizeEndInsert.msg", {descrizioneLayer:layer.descrizioneLayer});
		
		if (geometry.geometryIsValid){
			if (confirm(messint)) {
				this.validateDigitizeOperation(layer, function() {
					if ((this.paramsJS.azioniApertura.modoEditingSingolo != null ) && (this.paramsJS.azioniApertura.modoEditingSingolo != "" )) {
						var edGeom = this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry;
						if ((edGeom!=null) && (edGeom!="")) {
							// Se l'oggetto esiste vuol dire che l'inserimento si riferiva alla sola geometria (quindi e' un update)
							this.doEventActions(layer, this.eventUpdateGeom, this.paramsJS.azioniApertura.modoEditingSingolo.valoreChiave);
							this.digitizeLayerConditionalClear(layer, this.eventUpdateGeom);
						} else {
							// Se l'oggetto non esiste vuol dire che deve essere vero inserimento
							this.doEventActions(layer, this.eventIns, this.paramsJS.azioniApertura.modoEditingSingolo.valoreChiave);
							this.digitizeLayerConditionalClear(layer, this.eventIns);
						}
					} else {
						this.doEventActions(layer, this.eventIns, null);
						this.digitizeLayerConditionalClear(layer, this.eventIns);
					}
				},
				function (errMsg,isAjaxError) {
					if(isAjaxError){
						this.showAjaxError(errMsg);
					}else{
						alert (errMsg);					
					} 					
					this.digitizeLayerClear();	 		 
				})	 
			} else {
				this.digitizeLayerClear();	
			}
		} else {
			alert(ToloI18n.getMsg("ToloMapAPIExt.onDigitizeEndInsert.msgInvalidGeom"));
			this.digitizeLayerClear();
		}
		
		if ((this.paramsJS.azioniApertura.modoEditingSingolo != null ) && (this.paramsJS.azioniApertura.modoEditingSingolo != "" )) {
			this.bEditingSingoloInsertDone=true;
		}
		
		this.fireEvent("digitizeEndInsert", geometry);
	},

	/**
	 * Cancella tutto il contenuto del layer di digitalizzazione se è previsto da configurazione (file preset) questo comportamento a fine digitalizzazione.
	 * Nel caso che non sia prevista la cancellazione attiva l'editing se previsto nel file di preset 
	 * 
	 * @param {} eventoLayer
	 * @param {} tipoEvento
	 */
	digitizeLayerConditionalClear: function(eventoLayer, tipoEvento) {
		
		var azioniEventi = this.getAzioniEventi(eventoLayer, tipoEvento);
		if (azioniEventi.digitizedFeatureClear) {
			this.digitizeLayerClear();
		} else {
			this.viewer.pluginStartDigitizedFeatureModify(azioniEventi.digitizedFeatureModifyMode);
			this.viewer.on('onDigitizedFeatureDragDropEnd', this.digitizedFeatureModifyEnd,this);
			this.viewer.on('onDigitizedFeatureVertexEditingEnd', this.digitizedFeatureModifyEnd,this);
			
		}
			
		
	},
	
	/**
	 * Cancella tutto il contenuto del layer di digitalizzazione e disabilita l'editing eventualmente attivato
	 */
	digitizeLayerClear: function() {
		this.viewer.pluginDigitizeLayerClear();
		this.viewer.pluginStopDigitizedFeatureModify();
		this.viewer.un('onDigitizedFeatureDragDropEnd',this.digitizedFeatureModifyEnd, this);
		this.viewer.un('onDigitizedFeatureVertexEditingEnd', this.digitizedFeatureModifyEnd, this);
	},
	
	/**
	 * Method: onDigitizeEndAdd
	 * Funzione chiamata alla fine del processo di digitalizzazione nel caso che l'operazione sia una aggiunta di poligono. Viene invocata dalla funzione più generale onDigitizeEndGeometry etc.
	 * Si occupa di chiedere conferma ed eventualmente eseguire le azioni richieste invocando la doEventActions
	 *
	 * Parameters:
	 * geometry - {JSGeometry} la geometria.
	 */
	onDigitizeEndAdd: function (geometry){

	 	var layer = this.getCurrentSelectLayer();
	 	//ALE1
	 	// Assumo che esista e che sia uno solo perchè altrimenti non dovrebbe essere abilitato il pulsante che 
	 	// ha dato origine a questa azione
	 	var selCorrente = this.selezioneCorrente.getByCodTPN(layer.codTPN).geometries[0];
	 	var chiaveSelCorrente =  selCorrente.key;
		var messint = ToloI18n.getMsg("ToloMapAPIExt.onDigitizeEndAdd.msg", {descrizioneLayer: layer.descrizioneLayer});
		if (confirm(messint)) {
			this.validateDigitizeOperation(layer, function() {
											this.doEventActions(layer, this.eventUpdateGeom,  chiaveSelCorrente, undefined, undefined, undefined, selCorrente);
											this.digitizeLayerConditionalClear(layer, this.eventUpdateGeom);
												  }, 
											function (errMsg,isAjaxError) {
												if(isAjaxError){
													this.showAjaxError(errMsg);
												}else{
													alert (errMsg);					
												} 					
												this.digitizeLayerClear();			 
											}	 
									) 	
		} else { 
			this.digitizeLayerClear();		
		}
		this.fireEvent("digitizeEndAdd", geometry);
	},

	/**
	 * Method: validateDigitizeOperation
	 * Valida la digitazione.
	 * 
	 * Parameters:
	 * layer - {} il layer.
	 * funcSuccess - {Function} funcSuccess
	 * funcError - {Function} funcError
	 */
	validateDigitizeOperation: function (layer, funcSuccess, funcError) {
			
		if (layer.validazioneGeometria) {
			//Chiamata ajax
			var ajaxOptions = { method: 'post',
								url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxGeometryValidationServlet',
								scope: this,
								params: {geoOp: this.geoOpField.getValue(), 
											 geoCoord: this.geoCoordField.getValue(),
											 codTPN:   layer.codTPN,
											 format: 'ext',
											 urlAdditionalParams: this.paramsJS.urlAdditionalParams,
											 paramPreset: this.paramsJS.nomePreset
											 },
								success: function(results, store) {
												 
												//var resp = eval('(' + transport.responseText + ')');
												//var errori = resp.errori;
												 
												if (results.length==0) {
													funcSuccess.call(this);
												} else {
													//Errore di validazione
													var errMsg = results[0].data.errorMessage;
													for (i=1;  i<results.length; i++) {
														errMsg += '\n' + results[i].data.errorMessage;
													}
													if(funcError){ 
														// Passa il messaggio di errore e dice che l'errore NON è Ajax
														funcError.call(this,errMsg,false); 
													}else{
														alert (errMsg);
													}												
												}				
										  },
								failure: function (store) { 
											//validateDigitizeOperation.showAjaxError(transport);
											if(funcError){ 
												// Passa il messaggio di errore e dice che l'errore è Ajax
												funcError.call(this,ToloI18n.getMsg("ToloMapAPIExt.validateDigitizeOperation.httperr"),true);
											}else{
												this.showAjaxError(transport);
											} 
										 } 
							  }
	
			// Aggiunta parametri WMS da url
			Ext.apply(ajaxOptions.params, this.paramsJS.urlAdditionalParams);
			
			new TolomeoExt.ToloCrossAjax().request(ajaxOptions);
			
		} else {
			funcSuccess.call(this);
		}
	},
	

	/**
	 * Method: digitizeEndVertexEdit
	 * Funzione chiamata alla fine del processo di digitalizzazione nel caso che l'operazione sia una modifica dei vertici. Viene invocata dalla funzione più generale onDigitizeEndGeometry etc.
	 * Si occupa di chiedere conferma ed eventualmente eseguire le azioni richieste invocando la doEventActions
	 *
	 * Parameters:
	 * geometry - {JSGeometry} la geometria.
	 */
	digitizeEndVertexEdit: function (geometry){

	 	var layer = this.getCurrentSelectLayer();
	 	 // Assumo che esista e che sia uno solo perchè altrimenti non dovrebbe essere abilitato il pulsante che 
	 	// ha dato origine a questa azione
	 	var selCorrente = this.selezioneCorrente.getByCodTPN(layer.codTPN).geometries[0];
	 	var chiaveSelezione =  selCorrente.key;
		//var chiaveSelezione = selezioneCorrente.key;
		var messint = ToloI18n.getMsg("ToloMapAPIExt.digitizeEndVertexEdit.msg", {descrizioneLayer: layer.descrizioneLayer});
		if (confirm(messint)) {
			this.validateDigitizeOperation(	layer, 
									  	function() {
											this.doEventActions(layer, this.eventUpdateGeom,  chiaveSelezione, undefined, undefined, undefined, selCorrente);},
										function (errMsg,isAjaxError) { 
											if(isAjaxError){
												this.showAjaxError(errMsg);
											}else{
												alert (errMsg);		
												this.refreshSelected();			
											} 					 
										}) 
			
			}else{
				this.refreshSelected();
			}
		this.fireEvent("digitizeEndVertexEditing",  geometry);
		
	},

	/**
	 * Method: digitizeEndDragDrop
	 * Funzione chiamata alla fine del processo di digitalizzazione nel caso che l'operazione sia un drag drop. Viene invocata dalla funzione più generale onDigitizeEndGeometry etc.
	 * Si occupa di chiedere conferma ed eventualmente eseguire le azioni richieste invocando la doEventActions
	 *
	 * Parameters:
	 * geometry - {JSGeometry} geometry
	 */
	digitizeEndDragDrop: function (geometry){

	 	var layer = this.getCurrentSelectLayer();
	 	//var chiaveSelCorrente =  selezioneCorrente.key;
	 	// Assumo che esista e che sia uno solo perchè altrimenti non dovrebbe essere abilitato il pulsante che 
	 	// ha dato origine a questa azione
	 	var selCorrente = this.selezioneCorrente.getByCodTPN(layer.codTPN).geometries[0]
	 	var chiaveSelCorrente =  selCorrente.key;
		
		var messint = ToloI18n.getMsg("ToloMapAPIExt.digitizeEndDragDrop.msg", {descrizioneLayer: layer.descrizioneLayer});
		if (confirm(messint)) {
			this.validateDigitizeOperation(layer, 
										function() {
												this.doEventActions(layer, this.eventUpdateGeom,  chiaveSelCorrente, undefined, undefined, undefined, selCorrente);  },
										function (errMsg,isAjaxError) { 
											if(isAjaxError){
												this.showAjaxError(errMsg);
											}else{
												alert (errMsg);		
												this.refreshSelected();			
											} 					 
										}) 
			
		}else{
			this.refreshSelected();
		}
		this.fireEvent('digitizeEndDragDrop', geometry);
		
	},

	/**
	 * Method: onDigitizeEndSubtract
	 * Funzione chiamata alla fine del processo di digitalizzazione nel caso che l'operazione sia una sottrazione di poligono. 
	 * Viene invocata dalla funzione più generale onDigitizeEndGeometry etc.
	 * Si occupa di chiedere conferma ed eventualmente eseguire le azioni richieste invocando la doEventActions.
	 * 
	 */
	onDigitizeEndSubtract: function (geometry){

		var layer = this.getCurrentSelectLayer();
		//var chiaveSelCorrente =  selezioneCorrente.key;
		// Assumo che esista e che sia uno solo perchè altrimenti non dovrebbe essere abilitato il pulsante che 
	 	// ha dato origine a questa azione
		var selCorrente = this.selezioneCorrente.getByCodTPN(layer.codTPN).geometries[0];
		var chiaveSelCorrente =  selCorrente.key;
		var messint = ToloI18n.getMsg("ToloMapAPIExt.onDigitizeEndSubtract.msg", {descrizioneLayer: layer.descrizioneLayer});
		if (confirm(messint)) {
			this.validateDigitizeOperation(layer, 
								function() {
									this.doEventActions(layer, this.eventUpdateGeom,  chiaveSelCorrente, undefined, undefined, undefined, selCorrente);  
									this.digitizeLayerConditionalClear(layer, this.eventUpdateGeom);
									},
									function (errMsg,isAjaxError) {
										if(isAjaxError){
											this.showAjaxError(errMsg);
										}else{
											alert (errMsg);					
										} 					
										this.digitizeLayerClear();			 
									}) 
			
			
		} else { 
			this.digitizeLayerClear();		
		}
		this.fireEvent("digitizeEndSubtract", geometry);

	},

	/**
	 * Method: onDigitizeEndAddSub
	 * Funzione chiamata alla fine del processo di digitalizzazione nel caso che l'operazione sia una aggiunta e sottrazione (operazione su coperture) di poligono. 
	 * Viene invocata dalla funzione più generale onDigitizeEndGeometry etc.
	 * Si occupa di chiedere conferma ed eventualmente eseguire le azioni richieste invocando la doEventActions.
	 * 
	 * See Also:
	 * <doEventActions>
	 */
	onDigitizeEndAddSub: function (geometry){

		var layer = this.getCurrentSelectLayer();
		//var chiaveSelCorrente =  selezioneCorrente.key;
		// Assumo che esista e che sia uno solo perchè altrimenti non dovrebbe essere abilitato il pulsante che 
	 	// ha dato origine a questa azione
		var selCorrente = this.selezioneCorrente.getByCodTPN(layer.codTPN).geometries[0];
	 	var chiaveSelCorrente =  selCorrente.key;
	 	var messint = ToloI18n.getMsg("ToloMapAPIExt.onDigitizeEndAddSub.msg", {descrizioneLayer: layer.descrizioneLayer});
		
		if (confirm(messint)) {
			this.validateDigitizeOperation(layer, 
						function() {
				
											        
								this.doEventActions(layer, this.eventUpdateGeom,  chiaveSelCorrente, undefined, undefined, undefined, selCorrente); 
								this.digitizeLayerConditionalClear(layer, this.eventUpdateGeom);
									},
									function (errMsg,isAjaxError) {
										if(isAjaxError){
											this.showAjaxError(errMsg);
										}else{
											alert (errMsg);					
										} 					
										this.digitizeLayerClear();			 
									})
		} else { 
			this.digitizeLayerClear();		
		}
		this.fireEvent("digitizeEndAddSub", geometry);
	},

	/**
	 * Method: onDigitizeStartInsert
	 * Funzione invocata per iniziare la digitalizzazione relativa ad una operazione di inserimento.
	 * 
	 */
	onDigitizeStartInsert:function () {
		this.digitizeStart(this.getCurrentSelectLayer().tipoGeometria);
	},

	/**
	 * Method: onDigitizeStopInsert
	 * Funzione invocata per interrompere (annullare) la digitalizzazione relativa ad una operazione di inserimento.
	 * Non confondere con onDigitizeEndInsert che è la fine regolare della digitalizzazione.
	 * 
	 */
	onDigitizeStopInsert: function () {
		this.digitizeStop(this.getCurrentSelectLayer().tipoGeometria);
	},
	
	/**
	 * Method: onDigitizeByCADStartInsert
	 * Funzione invocata per iniziare la digitalizzazione per mezzo di ACD relativa ad una operazione di inserimento.
	 * 
	 */
	onDigitizeByCADStartInsert:function () {
		this.digitizeByCADStart(this.getCurrentSelectLayer().tipoGeometria);
	},

	/**
	 * Method: onDigitizeByCADStopInsert
	 * Funzione invocata per interrompere (annullare) la digitalizzazione per mezzo di CAD relativa ad una operazione di inserimento.
	 * Non confondere con onDigitizeEndInsert che è la fine regolare della digitalizzazione.
	 * 
	 */
	onDigitizeByCADStopInsert: function () {
		this.digitizeByCADStop(this.getCurrentSelectLayer().tipoGeometria);
	},

	/**
	 * Method: onDigitizeStartSubtract
	 * Funzione invocata per iniziare la digitalizzazione relativa ad una operazione di sottrazione.
	 * 
	 */
	onDigitizeStartSubtract: function () {
		var modLayer = this.getCurrentSelectLayer();
		if (modLayer.tipoGeometria==geomTypePoint) {
			this.digitizeStart(geomTypePolygon);
		} else {
			this.digitizeStart(modLayer.tipoGeometria);
		}
	},

	/**
	 * Method: onDigitizeStopSubtract
	 * Funzione invocata per fermare (annullare) la digitalizzazione relativa ad una operazione di sottrazione.
	 * 
	 */
	onDigitizeStopSubtract: function () {
		var modLayer = this.getCurrentSelectLayer();
		if (modLayer.tipoGeometria==geomTypePoint) {
			this.digitizeStop(geomTypePolygon);
		} else {
			this.digitizeStop(modLayer.tipoGeometria);
		}

	},

	/**
	 * Method: onDigitizeStartAdd
	 * Funzione invocata per iniziare la digitalizzazione relativa ad una operazione di aggiunta.
	 * 
	 */
	onDigitizeStartAdd: function () {
	    var modLayer = this.getCurrentSelectLayer();
	    this.digitizeStart(modLayer.tipoGeometria);
	},

	/**
	 * Method: onDigitizeStopAdd
	 * Funzione invocata per fermare la digitalizzazione relativa ad una operazione di aggiunta.
	 * 
	 */
	onDigitizeStopAdd: function () {
	    var modLayer = this.getCurrentSelectLayer();
	    this.digitizeStop(modLayer.tipoGeometria);
	},

	/**
	 * Method: onDigitizeStartAddSub
	 * Funzione invocata per iniziare la digitalizzazione relativa ad una operazione di aggiunta/sottrazione (operazione su copertura).
	 * 
	 */
	onDigitizeStartAddSub: function () {
	    var modLayer = this.getCurrentSelectLayer();
	    this.digitizeStart(modLayer.tipoGeometria);
	},

	/**
	 * Method: onDigitizeStopAddSub
	 * Funzione invocata per fermare (annullare) la digitalizzazione relativa ad una operazione di aggiunta/sottrazione (operazione su copertura).
	 * 
	 */
	onDigitizeStopAddSub: function () {
	    var modLayer = this.getCurrentSelectLayer();
	    this.digitizeStop(modLayer.tipoGeometria);
	},

	/**
	 * Method: onDigitizeStartVertexEdit
	 * Funzione invocata per iniziare la modifica dei vertici.
	 */
	onDigitizeStartVertexEdit: function () {
	    var modLayer = this.getCurrentSelectLayer();
	    this.digitizeStartVertexEditing(modLayer.tipoGeometria);

	},
	
	/**
	 * Method: onDigitizeStopVertexEdit
	 * Funzione invocata per fermare (annullare) la modifica dei vertici.
	 * 
	 */
	onDigitizeStopVertexEdit: function () {
	    var modLayer = this.getCurrentSelectLayer();
	    this.digitizeStopVertexEditing(modLayer.tipoGeometria);
	},

	/**
	 * Method: onDigitizeStartDragDrop
	 * Funzione invocata per lo spostamento di un oggetto.
	 * 
	 */
	onDigitizeStartDragDrop: function () {
	    var modLayer = this.getCurrentSelectLayer();
	    this.digitizeStartDragDrop(modLayer.tipoGeometria);
	},

	/**
	 * Method: onDigitizeStopDragDrop
	 * Funzione invocata per fermare (annullare) lo spostamento di un oggetto.
	 * 
	 */
	onDigitizeStopDragDrop:function () {
	    var modLayer = this.getCurrentSelectLayer();
	    this.digitizeStopDragDrop(modLayer.tipoGeometria);
	},

	/**
	 * Method: digitizeStart
	 * Inizia la digitalizzazione (invocata dalle onDigitizeStartAddSub etc.)
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeStart: function (geomType){

		switch (geomType) {
	   		case geomTypePoint:
	   			this.viewer.pluginStartDigitizePoint(geomType);
	   		break;
	   		case geomTypeLine:
	   			this.viewer.pluginStartDigitizeLine(geomType);
	   		break;
	   		case geomTypePolygon:
	   			this.viewer.pluginStartDigitizePolygon(geomType);
	   		break;
	   		case geomTypeCircle:
	   			this.viewer.pluginStartDigitizeCircle(geomType);
	   		break;

	   	}
	},		

	/**
	 * Method: digitizeStop
	 * Interrompe (annulla) la digitalizzazione (invocata dalle onDigitizeStartAddSub etc.)
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeStop: function (geomType){

		switch (geomType) {
	   		case geomTypePoint:
	   			this.viewer.pluginStopDigitizePoint(geomType);
	   		break;
	   		case geomTypeLine:
	   			this.viewer.pluginStopDigitizeLine(geomType);
	   		break;
	   		case geomTypePolygon:
	   			this.viewer.pluginStopDigitizePolygon(geomType);
	   		break;
	   		case geomTypeCircle:
	   			this.viewer.pluginStopDigitizeCircle(geomType);
	   		break;

	   	}
	},
				
	/**
	 * Method: digitizeByCADStart
	 * Inizia la digitalizzazione (invocata dalle onDigitizeByCADStart etc.)
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeByCADStart: function (geomType){

		switch (geomType) {
	   		case geomTypePoint:
	   			//this.viewer.pluginStartDigitizePointFromRef(geomType);
	   			this.viewer.pluginStartDigitizePointByCAD(geomType);
	   		break;
	   		case geomTypeLine:
	   			this.viewer.pluginStartDigitizeLineByCAD(geomType);
	   		break;
	   		case geomTypePolygon:
	   			this.viewer.pluginStartDigitizePolygonByCAD(geomType);
	   		break;
	   		default:
	   			Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.digitizeByCADStart.title"), ToloI18n.getMsg("ToloMapAPIExt.digitizeByCADStart.msg"));
	   		break;
	   	}
	},
	
	/**
	 * Method: digitizeByCADStop
	 * Interrompe (annulla) la digitalizzazione per mezo di CAD
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeByCADStop: function (geomType){

		switch (geomType) {
	   		case geomTypePoint:
	   			//this.viewer.pluginStopDigitizePointFromRef(geomType);
	   			this.viewer.pluginStopDigitizePointByCAD(geomType);
	   		break;
	   		case geomTypeLine:
	   			this.viewer.pluginStopDigitizeLineByCAD(geomType);
	   		break;
	   		case geomTypePolygon:
	   			this.viewer.pluginStopDigitizePolygonByCAD(geomType);
	   		break;
	   		case geomTypeCircle:
	   			Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.digitizeByCADStop.title"), ToloI18n.getMsg("ToloMapAPIExt.digitizeByCADStop.msg"));
	   		break;

	   	}
	},

	/**
	 * Method: digitizeStartVertexEditing
	 * Inizia la modifica dei vertici.
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeStartVertexEditing: function (geomType){

		this.viewer.pluginStartVertexEditing(geomType, this.getCurrentSelectLayer().codTPN);

	},

	/**
	 * Method: digitizeStopVertexEditing
	 * Ferma (annulla) la modifica dei vertici.
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeStopVertexEditing: function (geomType){

		this.viewer.pluginStopVertexEditing(geomType);

	},

	/**
	 * Method: digitizeStartDragDrop
	 * Inizia lo spostamento di un oggetto.
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeStartDragDrop: function (geomType){

		this.viewer.pluginStartDragDrop(geomType);
	},

	/**
	 * Method: digitizeStopDragDrop
	 * Ferma (annulla) lo spostamento di un oggetto.
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeStopDragDrop: function (geomType){

		this.viewer.pluginStopDragDrop(geomType);
	},

	/**
	 * Method: digitizeStopVertexEditing
	 * Ferma (annulla) l'editing dei vertici di un oggetto.
	 *
	 * Parameters:
	 * geomType - {} il tipo di geometria definito.
	 */
	digitizeStopVertexEditing: function (geomType){

		this.viewer.pluginStopVertexEditing(geomType);
	},

	/**
	 * Method: getAzioniEventi
	 * Ritorna la sezione AzioniEventi specifica di eventoLayer e del tipoLayer passati come parametro
	 *
	 * Parameters:
	 * eventoLayer - {} eventoLayer
	 * tipoEvento - {} tipoEvento
	 * idBtn - {} idBtn
	 *
	 * Returns:
	 *  {<AzioniEventi>} la sezione AzioniEventi specifica.
	 */
	getAzioniEventi: function (eventoLayer, tipoEvento, idBtn) {
		var azioniEventi = null;
		
		if (eventoLayer) {
			switch (tipoEvento) {
			  case (this.eventVis):
			  		azioniEventi = eventoLayer.azioniEventiVis;
			  		break;
			  case (this.eventCanc):
			  		azioniEventi = eventoLayer.azioniEventiCanc;
			  		break;
			  case (this.eventUpdateGeom):
			  		azioniEventi = eventoLayer.azioniEventiUpdateGeom;
			  		break;
			  case (this.eventUpdateAlpha):
			 		azioniEventi = eventoLayer.azioniEventiUpdateAlpha;
			  		break;
			  case (this.eventIns):
			  		azioniEventi = eventoLayer.azioniEventiIns;
			  		break;
			  case (this.eventInsFromLayer):
			  		azioniEventi = eventoLayer.azioniEventiInsFromLayer;
			  		break;
			  case (this.eventInsFromImport):
			  		azioniEventi = eventoLayer.azioniEventiInsFromImport;
			  		break;
			  case (this.eventRicerca):
			  		azioniEventi = eventoLayer;
			  		break;
		      case (this.eventCustomButton):		      		
			      	var azCbList = eventoLayer.azioniEventiCustomButtonList.customButtonList;
					for (var i=0; i<azCbList.length; i++) {
						if (azCbList[i].idCustomButton == idBtn) {
							azioniEventi = azCbList[i];
							// parametro che mi dice se l'azione è sul layer o globale
							if(azioniEventi)
								azioniEventi.isOfTheLayer = true;						
							break;
						}
					}
					if (!azioniEventi) {
						// se non definito a livello di layer/evento cerca su definizione globale bottoni
						var azCbList = this.paramsJS.layOut.customButtonList;
						for (var i=0; i<azCbList.length; i++) {
							if (azCbList[i].idCustomButton == idBtn) {
								azioniEventi = azCbList[i].azioniEventiCustomButton;
								// parametro che mi dice se l'azione è sul layer o globale
								if(azioniEventi)
									azioniEventi.isOfTheLayer = false;
								break;
							}
						}
					}
					
			  		break;
			}
		}
		
		return azioniEventi;
	},

	// TODO
	// - gestire in doEventActions chiudiSuDblClick e togliere da onIdentify
	// - gestire pluginRefreshMappa quando necessario (adesso lo fa sempre dopo l'ultimo passo)
	// - gestione parametri da uno step all'altro?
	// - gestione errori ajax
	/**
	 * Method: doEventActions
	 * Si occupa di eseguire le azioni previste per l'evento ed il layer specifici
	 * le azioni ajax sono eseguite in maniera sincrona (attesa della fine prima di passare alla successiva) 
	 * mentre le altre sono eseguite in maniera asincrona (senza attesa della fine) fino alla successiva ajax.
	 * N.B. Ricordarsi in caso di aggiunta di parametro di gestire anche all'interno dove vengono settati sulla funzione
	 * di callback e nella funzione di callback stessa e doEventActionsAjaxFailure
	 *
	 * Parameters:
	 * eventoLayer - {} corrispondente JS della classe parametriEventiLayer
	 * tipoEvento - {} tipo di evento che si e' verificato. Valori possibili sono quelli previsti per le costanti che indicano il tipo di evento
	 * keyValue - {} chiave dell'oggetto al quale si riferisce l'azione
	 * nStep - {} numero del passo. Nelle chiamate ajax la funzione termina per essere richiamata 
	 *            dalla funzione di callback ajax passando in questo parametro il passo al quale si è arrivati e consentendo quindi di andare avanti
	 * nextActionObj - {} oggetto contenente i parametri per l'eventuale azione di redirect. Una azione di redirect è caratterizzata dal fatto di avere
	 *   		          il flag redirect=true. Quando questo si verifica viene fatta redirect (tenendo conto di ajaxCall e traget) all'url definita in redirectUrl 
	 * 			          se definito oppure nel parametro nextActionObj.redirectUrl. Il contenuto del parametro nextActionObj.parameters viene in ogni caso
	 * 			          aggiunto ai parametri di chiamata dell'azione successiva (anche se non è una redirect)
	 * nSubEvento - {} umero di sottoevento, per esempio numero di ricerca, di custombutton etc. Indica la posizione nell'array.
	 * oggetto - {JSGeometry} oggetto al quale si riferisce l'azione
	 */
	doEventActions: function (eventoLayer, tipoEvento, keyValue, nStep, nextActionObj, idBtn, oggetto) {

		if ((nStep == null) || (nStep == undefined)) nStep = -1;
		
		nStep++;
		
		var azioniEventi = this.getAzioniEventi(eventoLayer, tipoEvento, idBtn);
		var bLastAction = (nStep==azioniEventi.azioneList.length);
		var azione = null;
		
		if (azioniEventi) {
			var bExit = false;
			if (azioniEventi.azioneList) {
				while ( (nStep<azioniEventi.azioneList.length) && !bExit ) {
					azione = azioniEventi.azioneList[nStep];
					
					if (azione.codeless) {
						this.fireEvent("codelessaction", eventoLayer, tipoEvento, oggetto);
					} else if (azione.viewCodeless && azione.viewCodeless.rigaList && azione.viewCodeless.rigaList.length > 0) {
						this.fireEvent("viewcodelessaction", eventoLayer, oggetto);
					} else {
						var url;
						var urlcompleta;
					
						 
					
						// definizione url
						/*
						if (azione.redirect) {
							if (nextActionObj.redirectUrl) {
								url = nextActionObj.redirectUrl;
							} else {
								url = azione.redirectUrl;
							}
						} else {
							url = azione.url;
						}
						*/
					
						if (azione.redirect) {
							if (nextActionObj.redirectUrl) {
								url = nextActionObj.redirectUrl;
							} else {
								url = azione.redirectUrl;
							}
						} else {
							// if (azione.useWMSGetFeatureInfo && oggetto.getFeatureInfoLink!=undefined && oggetto.getFeatureInfoLink!=null && oggetto.getFeatureInfoLink!="") {
							if (azione.useWMSGetFeatureInfo && oggetto.getFeatureInfoLink) {
								url = oggetto.getFeatureInfoLink;
								this.clearHighLigthed();
								if (oggetto.relatedGeoms!=undefined && oggetto.relatedGeoms!=null) this.addHighlighted(oggetto.relatedGeoms, false);
							} else { 						
								url = azione.url;
							}
						}
					
						if(!url) {
						
							this.fireEvent('visualize', eventoLayer.codTPN, keyValue);
						
						} else {
					
							/*
							// sostituzione dei valori #JS{} presenti nel tag <url> del file di preset						
							stringEx = /#JS{{1}[A-Z,a-z,0-9,_,., \/]*}/;
						    stringExInit= /^#JS{{1}/;
							stringExEnd= /}/;
							newJSUrl='';
							if (stringEx.test(url)) {
							   initStringIndex= url.search(stringExInit)+ 4;
							   endStringIndex= url.search(stringExEnd);
							   value= url.substring(initStringIndex, endStringIndex);
							   newJSUrl= url.replace(stringEx, eval(value));
							   url= newJSUrl;
							}
							*/
						
							// sostituzione dei valori #JS{} presenti nel tag <url> del file di preset
							var stringEx     = /#JS{{1}[A-Z,a-z,0-9,_,',",.,:,\?,=,!,<,>,\*,\(,\),\[,\],\^, \/]*}/;
						    var stringExInit = /#JS{{1}/;
							var stringExEnd  = /}/;
							var newJSUrl     = url;
							var suburl       = url;
							while (stringEx.test(suburl)) {
							
							   var initStringIndex = suburl.search(stringExInit);
							   var endStringIndex  = suburl.search(stringExEnd);
							   var name			   = suburl.substring(initStringIndex, endStringIndex+1);
							   var value           = suburl.substring(initStringIndex+4, endStringIndex);
							   newJSUrl			   = newJSUrl.replace(name, eval(value));
							   suburl 			   = (endStringIndex+2 <= suburl.length) ? suburl.substring(endStringIndex+2): "";
							   
							}
							url= newJSUrl;
						
							var questionMark = (url.indexOf("?") == -1) ? "?" : "";			
							urlcompleta = url + questionMark + "&" +  "IDTPN=" + escape(keyValue) + '&codTPN=' + escape(eventoLayer.codTPN);
						
							this.condizioneListToPostVar(azioniEventi);
						
							if((azione.forward != null) && (azione.forward != "")){
								urlcompleta += '&forward=' + escape(azione.forward);
							}
						
							if((azione.command != null) && (azione.command != "")){
								urlcompleta += '&command=' + escape(azione.command);
							}
						
							if((nextActionObj) && (nextActionObj.parameters!=null) && (nextActionObj.parameters!="")){
								for (var i=0; i<nextActionObj.parameters.length; i++){
									urlcompleta += '&' + nextActionObj.parameters[i].key + "=" + escape(nextActionObj.parameters[i].value);
								}
								//urlcompleta += '&' + escape(nextActionObj.parameters);
							}
						
							var method = (azione.method || 'POST').toUpperCase(); 
						
							if (!azione.ajaxCall) {
								// azione normale (non ajax)
								if (azione.noTolomeoDefaultParams) 
									this.openURL (url, azione.target, method, azione.noTolomeoDefaultParams);
								else
									this.openURL (urlcompleta, azione.target, method);
							} else {
								// azione ajax
								// è bloccante (si aspetta la fine per proseguire negli step
								// per questo bexit e' posto a true
							
								//salvataggio parametri per successivo passo da callback
								this.doEventActionsAjaxCallback.eventoLayer = eventoLayer;
								this.doEventActionsAjaxCallback.tipoEvento	= tipoEvento;
								this.doEventActionsAjaxCallback.keyValue	= keyValue;
								this.doEventActionsAjaxCallback.nStep		= nStep;
								this.doEventActionsAjaxCallback.idBtn		= idBtn;
								this.doEventActionsAjaxCallback.oggetto		= oggetto;
							
								//Chiamata ajax
								var ajaxOptions = {
									method: method,								
									url: urlcompleta,
									params: {
										geoOp: this.geoOpField.getValue(), 									
										geoCoord: method == 'POST' ? this.geoCoordField.getValue() : null,
										selectedList: this.selectedListField.getValue(),
										SRID: this.paramsJS.mappe.SRID,
										clippingCodTPN: eventoLayer.clippingCodTPN
									},
									scope: this,
									success: this.doEventActionsAjaxCallback,
									failure: this.doEventActionsAjaxFailure
								}
										
								if (azione.crossDomainAjax) {
									// Aggiunta parametro format='ext' in richiesta
									ajaxOptions.params.format = 'ext';
									new TolomeoExt.ToloCrossAjax().request(ajaxOptions);
								} else {
									Ext.Ajax.request(ajaxOptions);
								}
								bExit = true;
							}
						}
					}
					nStep++;
			
				}
				
				if ( bLastAction || 
				     (azione!=null && !azione.ajaxCall && nStep>=azioniEventi.azioneList.length )) {
					// dopo ultima azione...
					if (azioniEventi.refreshAtTheEnd) {
						this.viewer.pluginRefreshMap();
					}
					if (azioniEventi.closeAtTheEnd) {
						window.close();
					}
					
					if (azioniEventi.azioneList.length>0) {
						// se azioniEventi.azioneList.length=0 non sono state eseguite azioni quindi non ha senso fare nulla
						// ed è demandato alla gestione fatta probabilmente sull'evento actionsEnd
						switch (tipoEvento) {
						  case (this.eventVis):
		
						  		break;
						  case (this.eventCanc):
						  		this.clearSelected(false, eventoLayer.codTPN);
					  			this.refreshSelected();
						  		break;
						  case (this.eventUpdateGeom):
							  	this.refreshSelected();
						  		break;
						  case (this.eventUpdateAlpha):
							  	//this.refreshSelected();
						  		break;
						  case (this.eventIns):
							  	//this.refreshSelected();
						  		break;
						  case (this.eventInsFromLayer):
							    this.clearSelected(false);
							  	break;
						  case (this.eventInsFromImport):
							    this.clearSelected(false);
							  	break;
						  case (this.eventRicerca):
						  		break;
						  		
						}	
					}
					
			
				}
			}
		}
		
		if ((azioniEventi.azioneList.length==0) || (nStep>=azioniEventi.azioneList.length)) {
				// dopo ultima azione...anche se non ci sono azioni definite
				this.eventActionsEnd(keyValue, eventoLayer.codTPN);
		}
				
	},
	
	/**
	 * Eseguita a fine azioni.
	 *  - se definiti i campi di una form per ricevere i valori a fine azione provvede a settarli
	 *  - lancia l'evento actionsEnd 
	 * @param {String} keyValue
	 * @param {String} codTPN
	 */
	eventActionsEnd: function(IDTPN, codTPN) {
		
		var values = { geoOp: this.geoOpField.getValue(),
					   geoCoord: this.geoCoordField.getValue(),
					   geoParts: this.geoCoordParts.getValue(),
					   geomPartsAllFlag: this.geomPartsAllFlag.getValue(),
					   selectedList: this.selectedListField.getValue(),
					   IDTPN: IDTPN,
					   codTPN: codTPN};
		
		if (this.actionsEndReturnFields) {
        	for(var fieldName in this.actionsEndReturnFields){
        		if(this.actionsEndReturnFields[fieldName]){
        			var domField = Ext.fly(this.actionsEndReturnFields[fieldName]);
        			if(domField) domField.dom.value =  values[fieldName];
        		}
        	}
        }
        
        this.fireEvent("actionsEnd", values);
		
	},
	
	/**
	 * Eseguita quando una feature digitalizzata viene in un secondo momento modificata
	 * 
	 */
	digitizedFeatureModifyEnd: function(geom) {
		
		//TODOH Attenzione che l'utente potrebbe aver cambiato layer attivo!!!
		var	layer = this.getCurrentSelectLayer();
		
		geom.codTPN = layer.codTPN;
		geom.SRID = this.paramsJS.mappe.SRID;
		
		this.geometryToPostVar(geom);
		var domField = Ext.fly(this.actionsEndReturnFields['geoCoord']);
		if(domField) domField.dom.value =  this.geoCoordField.getValue();
        
		
		/* Se faccio così fa validazione ma se validazione non passa sparisce il punto
		 * this.currentDigitizeOperation = this.digitizeOperationInsert;
		this.onDigitizeEndGeometry(geom);
		
		 */
        this.fireEvent("digitizedFeatureModifyEnd", geom);
		
	},

	/**
	 * Method: doEventActionsAjaxCallback
	 * Funzione di callback per le chiamate ajax effettuate dalla funzione doEventActions. 
	 * Recupera i parametri e richiama doEventActions per effettuare il passo successivo.
	 *
	 * Parameters:
	 * transport - {} transport
	 */
	doEventActionsAjaxCallback: function (records, store, originalOptions) {
		// recupero eventuali parametri di ritorno ajax e gestione (passaggio ai successivi? 
		// TODO ALE var response = eval('(' + transport.responseText + ')');	
		var nextActionObj;
		// TODO ALE if (response) {
		// TODO ALE 	nextActionObj = response.nextAction;
		// TODO ALE }
		
		var tipoEvento = this.doEventActionsAjaxCallback.tipoEvento;
		var eventoLayer = this.doEventActionsAjaxCallback.eventoLayer
		var idBtn = this.doEventActionsAjaxCallback.idBtn;
		var nStep = this.doEventActionsAjaxCallback.nStep;
		var oggetto = this.doEventActionsAjaxCallback.oggetto;
		
		//var azioniEventi = this.getAzioniEventi(eventoLayer, tipoEvento, idBtn);
		//var azione = azioniEventi.azioneList[nStep];
		
		
		// Lancia l'evento. Se l'evento non è crossDomain records contiene trasport della chiamata normale e store non c'e'
		this.fireEvent("onEventActionAjaxSuccess", eventoLayer, tipoEvento, idBtn, nStep, records, store, oggetto);
		
		// Richiama doEventActions per eventuali step successivi
		// ripassandogli i parametri che erano stati salvati 
		this.doEventActions(eventoLayer,
							tipoEvento,
							this.doEventActionsAjaxCallback.keyValue,
							nStep,
							nextActionObj,
							idBtn,
							oggetto);
					   
	},

	/**
	 * Method: doEventActionsAjaxFailure
	 * Comunica l'errore, recupera i parametri e richiama doEventActions per effettuare il passo successivo.
	 *
	 * Parameters:
	 * transport - {} transport
	 */
	doEventActionsAjaxFailure: function (records, store, originalOptions) {
		this.showAjaxError(records);
		var nextActionObj;
		//ALE TODO
		// recupero eventuali parametri di ritorno ajax e gestione (passaggio ai successivi? 
		
		var tipoEvento = this.doEventActionsAjaxCallback.tipoEvento;
		var eventoLayer = this.doEventActionsAjaxCallback.eventoLayer
		var idBtn = this.doEventActionsAjaxCallback.idBtn;
		var nStep = this.doEventActionsAjaxCallback.nStep;
		var oggetto = this.doEventActionsAjaxCallback.oggetto;
		
		// Lancia l'evento. Se l'evento non è crossDomain records contiene trasport della chiamata normale e store non c'e'
		this.fireEvent("onEventActionAjaxFailure", eventoLayer, tipoEvento, idBtn, nStep, records, store, oggetto);
		
		// Richiama doEventActions per eventuali step successivi
		// ripassandogli i parametri che erano stati salvati 
		this.doEventActions(this.doEventActionsAjaxCallback.eventoLayer,
				this.doEventActionsAjaxCallback.tipoEvento,
				this.doEventActionsAjaxCallback.keyValue,
				this.doEventActionsAjaxCallback.nStep,
				nextActionObj,
				this.doEventActionsAjaxCallback.idBtn,
				this.oggetto);
					   
	},
	
	/**
	 * Method: openURLRaw
	 *
	 * Parameters:
	 * url - {String} url su cui fare il submit
	 * target - {String} target sul quale aprire la url
	 * noTolomeoDefaultParams - {boolean} indica se includere o meno i parametri di default di tolomeo (attivo solo con method=GET
	 * 
	 */
	openURLRaw: function(url, target, method, noTolomeoDefaultParams) {
		
		var form = this.submitForm.getForm();
		//console.log("apro con metodo " + method + " la url " + completeUrl);
				
		if(method && method.toUpperCase() == 'GET'){
			var valuesObj = form.getValues();
			var completeUrl = url;
			completeUrl += (completeUrl.indexOf("?") == -1) ? "?" : "";
			
			if (noTolomeoDefaultParams==null || noTolomeoDefaultParams==false) {
				// si escludono le coordinate per i limiti del get
				for(var i in valuesObj){
					//&&(i != "selectedList")
					if ((i != "geoCoord")){
						completeUrl += "&" + i + "=" + encodeURIComponent(valuesObj[i]);
					}
				}	
			}
			window.open(completeUrl,target);
			
		} else {

			var submitParams = {
	               			method: 'POST',
	               			target: target,
	            			url: url
	               		}
	               		
	        form.submit(submitParams);
	               		
	        /*
			var formDom = form.getEl().dom;
			formDom.action = url;
			formDom.method = 'POST';
			formDom.target = target;		
			form.submit();*/
		}
	},
	
	/**
	 * Method: openURL
	 * Esegue il submit su una certa url e su un determinato target. Nella form sono presenti i campi geoCoord e geoOp.
	 *
	 * Parameters:
	 * url - {String} url su cui fare il submit
	 * target - {String} target sul quale aprire la url
	 * noTolomeoDefaultParams - {boolean} indica se includere o meno i parametri di default di tolomeo (attivo solo con method=GET
	 * 
	 */
	openURL: function (url, target, method, noTolomeoDefaultParams) {
		if(this.fireEvent("beforeOpenUrl", url, target) === false)
			return;
		/*if (target!="pannello")*/
		this.openURLRaw(url, target, method, noTolomeoDefaultParams);
		this.fireEvent("openUrl", url, target);
		
	},

	/**
	 * Method: clearURL
	 * Esegue il submit su una certa url e su un determinato target. Nella form sono presenti i campi geoCoord e geoOp.
	 *
	 * Parameters:
	 * target - {String} target sul quale aprire la url
	 * method - {String} metodo per la chiamata (GET o POST)
	 */
	clearURL: function (target, method) {
		var url = (this.paramsJS.azioniApertura.urlPannello) ? this.paramsJS.azioniApertura.urlPannello : this.TOLOMEOServer + this.TOLOMEOStaticRoot + "html/blank.html";		
		if(this.fireEvent("beforeClearUrl", url, target) === false)
			return;		
		/*if (target!="pannello")*/
		this.openURLRaw(url, target, method, true);
		this.fireEvent("clearUrl", url, target);
		
	},
	
	/**
	 * Method: geoOpToPostVar
	 * Setta l'operazione nella form per la trasmissione.
	 *
	 * Parameters:
	 * geoOp - {Ext.form.TextField} geoOp operazione (vedi costanti)
	 */
	geoOpToPostVar: function (geoOp){
		
		this.geoOpField.setValue(geoOp);
		
		//submitForm.geoOp.value = geoOp;
	},

	/**
	 * Method: geometryToPostVar
	 * Setta la geometrie nella form per la trasmissione alla servlet.
	 *
	 * Parameters:
	 * jsGeometry - {JSGeometry} jsGeometry Geometria
	 */
	geometryToPostVar : function (jsGeometry) {
		
		 this.geoCoordField.setValue(jsGeometry)
			
	},	
	
	/**
	 * Method: geomPartsToPostVar
	 * Setta geomParts nella form per la trasmissione alla servlet.
	 *
	 * Parameters:
	 * geomParts - {JSGeometryAttay} 
	 */
	geomPartsToPostVar : function (geomParts) {
		
		 this.geoCoordParts.setValue(geomParts)
			
	},
	
	/**
	 * Method: geomPartsAllFlagToPostVar
	 * Setta partsAllFlag (flag che indica se le parti presenti nella geomParts sono tutte) nella form per la trasmissione alla servlet.
	 *
	 * Parameters:
	 * partsAllFlag - {boolean} partsAllFlag
	 */
	geomPartsAllFlagToPostVar : function (partsAllFlag) {
		
		 this.geomPartsAllFlag.setValue(partsAllFlag)
			
	},

	/**
	 * Method: condizioneListToPostVar
	 * Setta nella form i valori delle chiavi relative agli oggetti selezionati e richiesti dalla condizioneList 
	 * dell'azioneEvento. Il formato utilizzato e' il seguente.
	 *
	 * <![CDATA[
	 * <condizioneList>
	 * 		<layer>
	 * 			<codTPN>-900</codTPN>
	 * 			<IDTPN>1000</IDTPN>
	 * 			<IDTPN>1002</IDTPN>
	 * 		</layer> 
	 * 		<layer>
	 * 			<codTPN>-1000</codTPN>
	 * 			<IDTPN>12</IDTPN>
	 * 			<IDTPN>13</IDTPN>
	 * 			<IDTPN>112</IDTPN>
	 * 		</layer>
	 * </condizioneList>
	 * ]]>
	 *
	 * dove 
	 *
	 * -900 e -1000 sono i codTPN di due layer indicati nella codnizioneList
	 * 1000 e 1002 sono gli oggetti selezionati appartenenti al layer -900 
	 * 12, 134 e 112 sono gli oggetti selezionati appartenenti al layer -1000 
	 *
	 * Parameters:
	 * azioniEventi - {} azioniEventi
	 */
	condizioneListToPostVar: function (azioniEventi) {
		
		if (azioniEventi.condizioneList) {
			var condList = azioniEventi.condizioneList;
			var condListParam = "<condizioneList>";
			for (var i=0; i<condList.length; i++) {
				var cond = condList[i];
				var selezionati = this.selezioneCorrente.getByCodTPN(cond.codTPN).geometries;
				if ((selezionati!=null) && (selezionati.length>0)) {
					condListParam += "<layer><codTPN>" + cond.codTPN + "</codTPN>" ;
					for (var j=0; j<selezionati.length; j++) {
						condListParam += "<IDTPN>" + selezionati[j].key + "</IDTPN>" ;
					}
					condListParam += "</layer>" ;
				}
			}
			condListParam += "</condizioneList>" ;
		}
		
		this.selectedListField.setValue(condListParam);
		//submitForm.selectedList.value = condListParam;
		
	},

	/**
	 * Method: verifyEventsSelectedConditions
	 *
	 * Parameters:
	 * eventoLayer - {} eventoLayer 
	 * tipoEvento - {} tipoEvento 
	 * nSubEvento - {} nSubEvento
	 */
	verifyEventsSelectedConditions: function (eventoLayer, tipoEvento, nSubEvento) {
		return this.eventsSelectedConditionsfullCheck(eventoLayer, tipoEvento, nSubEvento).ok;
	}, 

	/**
	 * Method: messageEventsSelectedConditions
	 *
	 * Parameters:
	 * eventoLayer - {} eventoLayer 
	 * tipoEvento - {} tipoEvento 
	 * nSubEvento - {} nSubEvento
	 */
	messageEventsSelectedConditions: function (eventoLayer, tipoEvento, nSubEvento) {
		return this.eventsSelectedConditionsfullCheck(eventoLayer, tipoEvento, nSubEvento).disabledMessage;	
	},

	/**
	 * Method: eventsSelectedConditionsfullCheck
	 * Verifica se sono rispettate le condizioni per abilitare un certo evento 
	 * (limitatamente agli oggetti selezionati) ed il messaggio con le motivazioni se le condizioni non siano rispettate 
	 * contiene il messaggio con le motivazioni. Ogni motivazione viene aggiunta alla precedente.
	 *
	 * Parameters:
	 * eventoLayer - {} eventoLayer 
	 * tipoEvento - {} tipoEvento 
	 * nSubEvento - {} nSubEvento
	 */
	eventsSelectedConditionsfullCheck: function (eventoLayer, tipoEvento, nSubEvento) {
		var ret = true;
		var disabledMessage = "";
		
		var azioniEventi = this.getAzioniEventi(eventoLayer, tipoEvento, nSubEvento);
		
		switch (tipoEvento) {
			 case (this.eventVis):
			 case (this.eventCanc):
			 case (this.eventUpdateGeom):
			 case (this.eventUpdateAlpha):
			
				   // verifica se selezionato un oggetto del corrispondente codTPN
				   // Tolto per consentire corretto funzionamento 
				   if (eventoLayer && !this.selezioneCorrente.ContainsCodTPN(eventoLayer.codTPN)) {
				   		disabledMessage += ToloI18n.getMsg("ToloMapAPIExt.digitizeByCADStop.evSelCondFullChck.msg1");	
				   		ret=false;
				   }
				   break;
			 case (this.eventCustomButton): 
			 /*
			 	if(nSubEvento==-1) {
			 		ret = true;
			 		break;
			 	}
			 */	
			 	// se non ci sono azioni eventi non si fa apparire il pulsante
			 	if(!azioniEventi) {
			 		ret = false;
			 	// se l'azione è del layer e non global si richiede la selezione di almeno un elemento del layer
			 	}else if (azioniEventi.isOfTheLayer && !this.selezioneCorrente.ContainsCodTPN(eventoLayer.codTPN)) {
				   	disabledMessage += ToloI18n.getMsg("ToloMapAPIExt.digitizeByCADStop.evSelCondFullChck.msg2");
				   	ret=false;
				} 
			 break;
			 case (this.eventIns):	break;
			 case (this.eventInsFromLayer):
				 // Verifica che ci sia nella selezione corrente almeno un oggetto dei layer abilitati come sorgente
				 if (azioniEventi && azioniEventi.enabledLayerList) {
						var condList = azioniEventi.enabledLayerList;
						var buff = false;
						for (var i=0; i<condList.length; i++) {
							var cond = condList[i];
							if (this.selezioneCorrente.ContainsCodTPN(cond.codTPN)) {
								buff=true;
								break;
							}
						}
						if (!buff) {
							disabledMessage += ToloI18n.getMsg("ToloMapAPIExt.digitizeByCADStop.evSelCondFullChck.msg3");
							ret=false;
						}
				 }
				 
				 
				 break;
			 case (this.eventInsFromImport): break;
			 case (this.eventRicerca): break;
		}
		
		// In tutti i casi devono essere verificate le condizioni aggiuntive se presenti
		if (azioniEventi && azioniEventi.condizioneList) {
			var condList = azioniEventi.condizioneList;
			for (var i=0; i<condList.length; i++) {
				var cond = condList[i];
				if (!this.selezioneCorrente.ContainsCodTPN(cond.codTPN)) {
					disabledMessage += ToloI18n.getMsg("ToloMapAPIExt.digitizeByCADStop.evSelCondFullChck.msg1",{nomeLayer:cond.nomeLayer});	
					ret=false;
				}
			}
		}
		
		return {ok: ret, disabledMessage: disabledMessage} ;
	},
	
	/**
	 * Method: enablePermittedOp
	 *
	 * Parameters:
	 * opCode - {} opCode 
	 * bPermitted - {} bPermitted 
	 */
	enablePermittedOp: function(opCode, bPermitted) {
		eventName = (bPermitted ? 'onOperationEnable' : 'onOperationDisable' );
		this.fireEvent(eventName, opCode);
	},
	
	/**
	 * Method: togglePermittedOperations
	 * Modifica lo stato delle icone per renderlo coerente con le operazioni possibili in funzione dell'oggetto selezionato e del layer
	 * Tipo di editing singolo attivo. Valori possibili:
	 *  0 - nessun editing singolo 
	 *  1 - inserimento completo   
	 *  2 - inserimento di sola geometria
	 *  3 - modifica geometria
	 *
	 *  Se editingJSGeometry==null  -> inserimento completo di oggetto con layerCODTPN e valorechiave. Per effettuare l'inserimento vengono invocate 
	 *  le stesse azioni previste per l'inserimento normale
	 *  se editingJSGeometry!=null ma con geometria nulla -> viene abilitato l'inserimento della geometria, ma l'azione risultante sarà la stessa di una updateGeom
	 *  se editingJSGeometry!=null e con geometria non nulla -> vengono abilitate le azioni di update sulla geometria
	 */	 
	//TODO
	togglePermittedOperations: function () {

		var selLayer = this.getCurrentSelectLayer();
		var sctpn = this.paramsJS.getSelectableCodTPN();
		var withSnap = false;		
		
		
		// se nessun layer selezionato nascondi bottone di selezione
		this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnSeleziona, sctpn && sctpn.length > 0);

		var tipoEditingSingolo;
		
		// Stabilisco in quale modalità sono
		if ((this.paramsJS.azioniApertura.modoEditingSingolo != null) && (this.paramsJS.azioniApertura.modoEditingSingolo != "")) {
			if ((this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!=null) && 
				(this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry!="")) {
				var geoms = new JSGeometryArray();
				geoms.FromUntypedArray(this.paramsJS.azioniApertura.modoEditingSingolo.editingJSGeometry);
				if ((geoms.geometries.length==1) && (geoms.geometries[0].geometry!="")) {
					tipoEditingSingolo = 3;  // 3 - modifica geometria	
				} else {
					tipoEditingSingolo = 1;  // 2 - inserimento di sola geometria	
				} 	
			} else {
				tipoEditingSingolo = 1;  // 1 - inserimento completo  
			}
		} else {
			tipoEditingSingolo = 0; 	// 0 - nessun editing singolo
		}
		//selLayer.azioniEventiIns.noAction || selLayer.azioniEventiIns.azioneList.length
		if (selLayer && (selLayer.azioniEventiIns.forceEnable || selLayer.azioniEventiIns.azioneList.length!=0) && this.verifyEventsSelectedConditions(selLayer, this.eventIns) &&
			this.bEditingSingoloInsertDone == false &&
			(tipoEditingSingolo==0    ||
		     	tipoEditingSingolo==1 ||
		     	tipoEditingSingolo==2))  {
			//TODO
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnNuovo, true);
			
			withSnap = true;

		} else {
			//TODO
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnNuovo, false);
			// TODO var disMess = messageEventsSelectedConditions(selLayer, eventIns);
			// TODO if (disMess!="") bottoni[btnNuovo].disabledMessage ;
			
		}

		if (this.isPermittedInsFromLayer(selLayer, tipoEditingSingolo)) {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnNuovoDaLayer, true);
		} else {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnNuovoDaLayer, false);
			
		}

		if (this.isPermittedInsFromImport(selLayer, tipoEditingSingolo)) {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnNuovoDaImport, true);
		} else {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnNuovoDaImport, false);
		}
		
		/*
		if (selLayer && 
			(selLayer.azioniEventiInsFromLayer.forceEnable || selLayer.azioniEventiInsFromLayer.azioneList.length!=0) && 
			this.verifyEventsSelectedConditions(selLayer, this.eventInsFromLayer) &&
			this.bEditingSingoloInsertDone == false &&
			(tipoEditingSingolo==0    ||
			tipoEditingSingolo==1 ||
			tipoEditingSingolo==2))  {
			   this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnNuovoDaLayer, true);
		} else {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnNuovoDaLayer, false);
			
		}*/

		//selLayer.azioniEventiCanc.azioneList.length != 0
		if (selLayer && (selLayer.azioniEventiCanc.forceEnable || selLayer.azioniEventiCanc.azioneList.length != 0 ) && this.verifyEventsSelectedConditions(selLayer, this.eventCanc) && (tipoEditingSingolo == 0) ) {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnDelete, true);
			//bottoni[btnDelete].setEnabled(true);
		} else {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnDelete, false);
			//bottoni[btnDelete].setEnabled(false);
			// TODO var disMess = messageEventsSelectedConditions(selLayer, eventCanc);
			//TODO if (disMess!="") bottoni[btnDelete].disabledMessage = disMess;
		}  
		//selLayer.azioniEventiUpdateGeom.azioneList.length != 0
		if (selLayer && (selLayer.azioniEventiUpdateGeom.forceEnable || selLayer.azioniEventiUpdateGeom.azioneList.length != 0 ) && 
			 this.verifyEventsSelectedConditions(selLayer, this.eventUpdateGeom) && 
			 ((tipoEditingSingolo == 0) || 
			  (tipoEditingSingolo == 3  )))  {
			if (selLayer.copertura) {
				this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnAdd, false);
				this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnSubtract, false);
				this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnVertexEdit, false);
				this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnAddSub, true);

				// TODO bottoni[btnAdd].disabledMessage = "Funzione non disponibile su layer di tipo copertura";
				// TODO bottoni[btnSubtract].disabledMessage = "Funzione non disponibile su layer di tipo copertura";
				// TODO bottoni[btnAddSub].disabledMessage = "Funzione non disponibile su layer di tipo copertura";
				// TODO bottoni[btnVertexEdit].disabledMessage = "Funzione non disponibile su layer di tipo copertura";
				
			} else {
				if (selLayer.azioniEventiUpdateGeom.conAdd) this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnAdd, true); //bottoni[btnAdd].setEnabled(true);
					else this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnAdd, false); //bottoni[btnAdd].setEnabled(false);
				if (selLayer.azioniEventiUpdateGeom.conSubtract) this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnSubtract, true);  //bottoni[btnSubtract].setEnabled(true);
					else this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnSubtract, false); //bottoni[btnSubtract].setEnabled(false);
				this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnAddSub, false); //bottoni[btnAddSub].setEnabled(false);
				if (selLayer.azioniEventiUpdateGeom.conVertexEditing) this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnVertexEdit, true); //bottoni[btnVertexEdit].setEnabled(true);
					else this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnVertexEdit, false); // bottoni[btnVertexEdit].setEnabled(false);
				if (selLayer.azioniEventiUpdateGeom.conDragDrop) this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnDragDrop, true); //bottoni[btnDragDrop].setEnabled(true);
					else this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnDragDrop, false); //bottoni[btnDragDrop].setEnabled(false);
			}
			
			withSnap = true;			
			
		} else {
			// TODO var disMess = messageEventsSelectedConditions(selLayer, this.eventUpdateGeom);
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnAdd, false);
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnSubtract, false);
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnAddSub, false);
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnVertexEdit, false);
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnDragDrop, false);
			
			//TODO if (disMess!="") bottoni[btnAdd].disabledMessage = disMess;
			//TODO if (disMess!="") bottoni[btnSubtract].disabledMessage = disMess;
			//TODO if (disMess!="") bottoni[btnAddSub].disabledMessage = disMess;
			//TODO if (disMess!="") bottoni[btnVertexEdit].disabledMessage = disMess;
			//TODO if (disMess!="") bottoni[btnDragDrop].disabledMessage = disMess;
		} 
		//selLayer.azioniEventiUpdateAlpha.azioneList.length != 0
		if (selLayer && ((selLayer.azioniEventiUpdateAlpha.forceEnable || selLayer.azioniEventiUpdateAlpha.azioneList.length != 0 ) && this.verifyEventsSelectedConditions(selLayer, this.eventUpdateAlpha)) && (tipoEditingSingolo == 0)) {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnUpdateAlfa, true);
			//bottoni[btnUpdateAlfa].setEnabled(true);
		} else {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnUpdateAlfa, false);
			//bottoni[btnUpdateAlfa].setEnabled(false);
			//TODO if (disMess!="") bottoni[btnUpdateAlfa].disabledMessage = messageEventsSelectedConditions(selLayer, eventUpdateAlpha);
		}
		
		//if ((selLayer.azioniEventiVis.azioneList.length != 0) && bSelectedObjectLayerOK &&  (tipoEditingSingolo == 0)) {
		//selLayer.azioniEventiVis.azioneList.length != 0
		if (selLayer &&  (selLayer.azioniEventiVis.forceEnable || selLayer.azioniEventiVis.azioneList.length != 0) && this.verifyEventsSelectedConditions(selLayer, this.eventVis) &&  (tipoEditingSingolo == 0)) {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnIdentify, true);
			//bottoni[btnIdentify].setEnabled(true);
		} else {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnIdentify, false);
			// bottoni[btnIdentify].setEnabled(false);
			//TODO if (disMess!="") bottoni[btnIdentify].disabledMessage = messageEventsSelectedConditions(selLayer, eventVis);
		}  
		
		if(selLayer && selLayer.snappable && withSnap){
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnSnap, true);
		} else {
			this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnSnap, false);
		}	
		
		// CustomButtons TODO
		/* TODO TUTTO 
		for (var i=btnCustomBase; i<bottoni.length; i++) {
			var cb = bottoni[i];

				if  (selLayer && verifyEventsSelectedConditions(selLayer, eventCustomButton, cb.idCustomButton)  ) {
					cb.setEnabled(true);
				} else {
					cb.setEnabled(false);
					var disMess = messageEventsSelectedConditions(selLayer, eventCustomButton, cb.idCustomButton);
					if (disMess!="") cb.disabledMessage = disMess;
				}
		}
		*/
		
		for (var i = 0; i < this.paramsJS.layOut.customButtonList.length; i++) {
			var cb = this.paramsJS.layOut.customButtonList[i];
				if  (selLayer && this.verifyEventsSelectedConditions(selLayer, this.eventCustomButton, cb.idCustomButton)  ) {
					this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnCustomBase + i, true);
					//cb.setEnabled(true);
				} else {
					this.enablePermittedOp(TolomeoExt.ToloAPIOpCodes.btnCustomBase + i, false);
					//cb.setEnabled(false);
					//var disMess = messageEventsSelectedConditions(selLayer, eventCustomButton, cb.idCustomButton);
					//if (disMess!="") cb.disabledMessage = disMess;
				}
		}
		  
		
	},

	/**
	 * Method: isPermittedInsFromLayer
	 * Verifica se sul layer passato, nella modalità richiesta, è permesso l'inserimento da layer tenendo conto degli oggetti selezionati e delle impostazioni di preset
	 *
	 * Parameters:
	 * selLayer - {} layer su cui fare la verifica. 
	 * tipoEditingSingolo - {Number}  0 - nessun editing singolo, 1 - inserimento completo, 2 - inserimento di sola geometria, 3 - modifica geometria
	 * 
	 * 
	 * 
	 */
	isPermittedInsFromLayer: function(selLayer, tipoEditingSingolo){
		
		if (selLayer && selLayer.azioniEventiInsFromLayer &&
				(selLayer.azioniEventiInsFromLayer.forceEnable || selLayer.azioniEventiInsFromLayer.azioneList.length!=0) && 
				this.verifyEventsSelectedConditions(selLayer, this.eventInsFromLayer) &&
				this.bEditingSingoloInsertDone == false &&
				(tipoEditingSingolo==0    ||
				tipoEditingSingolo==1 ||
				tipoEditingSingolo==2))  {
				   return true;
		} else {
			return false;
			
		}
		
	},
	
	/**
	 * Method: isPermittedInsFromImport
	 * Verifica se sul layer passato, nella modalità richiesta, è permesso l'inserimento da import tenendo conto degli oggetti selezionati e delle impostazioni di preset
	 *
	 * Parameters:
	 * selLayer - {} layer su cui fare la verifica. 
	 * tipoEditingSingolo - {Number}  0 - nessun editing singolo, 1 - inserimento completo, 2 - inserimento di sola geometria, 3 - modifica geometria
	 * 
	 * 
	 * 
	 */
	isPermittedInsFromImport: function(selLayer, tipoEditingSingolo){
		                         
		if (selLayer && selLayer.azioniEventiInsFromImport &&
				(selLayer.azioniEventiInsFromImport.forceEnable || selLayer.azioniEventiInsFromImport.azioneList.length!=0) && 
				this.verifyEventsSelectedConditions(selLayer, this.eventInsFromImport) &&
				this.bEditingSingoloInsertDone == false &&
				(tipoEditingSingolo==0    ||
				tipoEditingSingolo==1 ||
				tipoEditingSingolo==2))  {
				   return true;
		} else {
			return false;
		}
	},
	
	
	/**
	 * Method: onChangeFromChoice
	 * Quando in fase di select sono presenti più oggetti e viene richiesta la scelta all'utente. Questa funzione viene chiamata quando la scelta cambia.
	 *
	 * Parameters:
	 * geom - {} la geometria. 
	 */
	onChangeFromChoice: function (geom){
		var geoms = new JSGeometryArray();
		geoms.geometries[0] = geom;
		this.addHighlighted(geoms);
	},
	
	/**
	 * Method: onSelectedFromChoice
	 * Quando in fase di select sono presenti più oggetti e viene richiesta la scelta all'utente. Questa funzione viene chiamata quando la scelta è stata effettuata.
	 *
	 * Parameters:
	 * geom - {} la geometria. 
	 */
	//TODO
	onSelectedFromChoice: function (geom,addToSelected,visualize) {
		
		this.clearHighLigthed(false);
		var combobox = document.getElementById("scelta");
		
		if (this.autoCloseChoiceWindow && this.selectedChoiceWindow) this.selectedChoiceWindow.close();
		
		var geoms = new JSGeometryArray();
		geoms.geometries[0] = geom; 
		
		this.addSelected(geoms,addToSelected,visualize);
	},

	/**
	 * Method: updateZoomToScale
	 * Aggiorna il valore della scala nel giusto campo.
	 *
	 * Parameters:
	 * scale - {} il valore di scala. 
	 */
	updateZoomToScale: function (scale){
		// TODO da provare la sostituzione con Ext
		Ext.get('scaleinput').value = Math.round(scale);
		//$('scaleinput').value = Math.round(scale);
	},
	
	// Autoidentify - INIZIO
	
	/**
	 * Method: autoIdentifyLayers
	 *
	 */
	autoIdentifyLayers: function () {
		var codTPNStr = "";
		for(var index=0; index<this.paramsJS.azioniEventi.eventiLayerList.length; index++) {
			var paramJSLayer = this.paramsJS.azioniEventi.eventiLayerList[index];
			if (paramJSLayer.autoIdentifyAllowed==true)  {
				if (this.TOCPanel.layerIsVisible(paramJSLayer.codTPN)==true) {
					codTPNStr += (codTPNStr!="") ? "," : "";
					codTPNStr += paramJSLayer.codTPN;
				}
			}
		}
		return codTPNStr;
	},

	/**
	 * Method: autoIdentifyLayersPresent
	 *
	 */
	autoIdentifyLayersPresent: function (){
		return (this.autoIdentifyLayers()=="") ? false : true;
	},

	/**
	 * Method: autoIdentifyLayersWithHighlight
	 *
	 * Parameters:
	 * codTPN - {} codTPN 
	 */
	autoIdentifyLayersWithHighlight: function (codTPN){
		var retVal = false;
		for(var index=0; index<this.paramsJS.azioniEventi.eventiLayerList.length; index++) {
			var paramJSLayer = this.paramsJS.azioniEventi.eventiLayerList[index];
			if ((paramJSLayer.autoIdentifyAllowed) && (paramJSLayer.autoIdentifyWithHighlight) && (
					(paramJSLayer.codTPN==codTPN) || (codTPN==undefined))) {
				retVal = true;
				break;
			}
		}
		return retVal;
	},

	/**
	 * Method: onAutoIdentify
	 *
	 * Parameters:
	 * point - {} il punto. 
	 * mouseX - {} coordinata x del mouse. 
	 * mouseY - {} coordinata y del mouse.
	 *  
	 */
	onAutoIdentify: function (point, mouseX, mouseY, mapXPixel, mapYPixel) {

		// raggio di tolleranza 6 pixel
		var tolleranceRange = this.viewer.pluginGetResolution() * 6;
			
		// Creazione elenco layer da interrogare
		var codTPNStr = this.autoIdentifyLayers();
		
		// TODO supportata solo mappa 0
		var nmappa = 0;
		var buff = codTPNStr.split(",");
		var stylesArr = new Array();
		
		for (var i=0; i<buff.length; i++) {
			var legendaInfo = this.paramsJS.getLegendaLayerInfoByCodTPN(buff[i], nmappa, (this.TOCPanel ? this.TOCPanel.tocInfo : null))			
			var stylebuff = (legendaInfo.tocInfoLayerInfo) ? legendaInfo.tocInfoLayerInfo.style : (legendaInfo.presetLayerInfo ? legendaInfo.presetLayerInfo.defaultStyle : "");  			
			stylesArr.push(stylebuff);
		}
		
		var styles = stylesArr.join(",");
		
		var mousePos = new Object();
		mousePos.mouseX = mouseX;
		mousePos.mouseY = mouseY;
		
		if (codTPNStr!="") {
			var bounds = this.viewer.pluginGetMapExtent();
			
			// Chiamata Ajax per effettuare l'intersezione e ricevere l'oggetto selezionato
			var ajaxOptions = {
				method: 'post',
				url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxSpatialQueryServlet',
				scope: this,
				mousePos: mousePos,
				params: {
					coordX: point.x, 
					coordY: point.y,
					codTPN: codTPNStr,
					styles: styles,
					range: tolleranceRange,
					SRID: this.paramsJS.mappe.SRID,
					format: 'ext',
					//Parametri aggiunti per GetFeatureInfo
					bbox:  bounds.left+","+bounds.bottom+","+bounds.right+","+bounds.top ,
					mapwidth:  this.viewer.pluginGetMapWidth()  ,
					mapheight: this.viewer.pluginGetMapViewerHeight() ,
					X: mapXPixel,
					Y: mapYPixel,
					paramPreset: this.paramsJS.nomePreset
				},
				success: this.ajaxAutoIdentifyOK,
				failure: this.showAjaxError 
			}

			// Aggiunta parametri WMS da url
			Ext.apply(ajaxOptions.params, this.paramsJS.urlAdditionalParams);
			new TolomeoExt.ToloCrossAjax().request(ajaxOptions);	
		}
	},

	/**
	 * Method: onAutoIdentifyCancel
	 * Provvede a chiudere la finestra di autoIdentify e fa il clear delle evidenziazioni.
	 *
	 */
	onAutoIdentifyCancel: function () {
		if (this.autoIdentifyWindow)
			this.autoIdentifyWindow.close();
		if (this.autoIdentifyLayersWithHighlight())
			this.clearAutoidentified();
	},

	/**
	 * Method: ajaxAutoIdentifyOK
	 * Funzione di callback per la chiamata ajax onMappaSelect {link #onMappaSelect} che identifica gli oggetti presenti in una certa posizione.
	 *
	 * Parameters:
	 * results - {} results 
	 * store - {} store 
	 * originalOptions - {} originalOptions 
	 */
	ajaxAutoIdentifyOK: function(results, store, originalOptions) {
		
		var geoms = new JSGeometryArray();
		geoms.FromStore(results, store);
		
		if (geoms.geometries.length==0) return;
		var szMessaggio = "";
		szMessaggio += '<ul>';
		for(var index=0; index<this.paramsJS.azioniEventi.eventiLayerList.length; index++) {
			var codTPN = this.paramsJS.azioniEventi.eventiLayerList[index].codTPN;
			var layerDesc = this.paramsJS.azioniEventi.eventiLayerList[index].descrizioneLayer;
			
			var g = geoms.getByCodTPN(codTPN);
			if (g!=null) {
				
				szMessaggio += '<li style="font-weight:bold">' + layerDesc + ':</li>';
				for (var i=0; i < g.geometries.length; i++) {
					szMessaggio += '<li style="margin-left:10px">' + g.geometries[i].description.replace(/\\\"/g,"\"") + '</li>';
				}
				if (this.autoIdentifyLayersWithHighlight(codTPN)) this.addAutoidentified(g);
			}
		}
		szMessaggio += "</ul>";

		if (this.autoIdentifyWindow!=null) this.autoIdentifyWindow.close(); 
		
		this.autoIdentifyWindow = Ext.create('Ext.Window', {
			html: szMessaggio,
			cls: 'clearCSS',
			bodyStyle: 'background-color:white;padding:2px',
			closable: false,
			draggable: false,
			maximizable: false,
			minimizable: false,
			resizable: false, 
			constrain: true,
			border: false
		}).show();
		
		if (Ext.isIE) {
			this.autoIdentifyWindow.setWidth(350);
		}
		
		var dialogWidth  = this.autoIdentifyWindow.getWidth() ;
		var dialogHeight = this.autoIdentifyWindow.getHeight();
		
		var viewerPos = this.viewer.getPosition();
		var mouseX = originalOptions.mousePos.mouseX - viewerPos[0];
		var mouseY = originalOptions.mousePos.mouseY - viewerPos[1];
		
		var dialogPosX = (mouseX+15+dialogWidth<this.viewer.getWidth()) ? originalOptions.mousePos.mouseX+15 : originalOptions.mousePos.mouseX-15-dialogWidth;
		var dialogPosY = (mouseY+dialogHeight<this.viewer.getHeight())  ? originalOptions.mousePos.mouseY    : originalOptions.mousePos.mouseY-dialogHeight;

		this.autoIdentifyWindow.setPosition(dialogPosX, dialogPosY);
	}, 

	/**
	 * Method: autoIdentifyEnable
	 *
	 * Parameters:
	 * bEnable - {} bEnable 
	 */
	autoIdentifyEnable: function (bEnable) {
		this.viewer.pluginAutoIdentifyEnable(bEnable);
	},
			
	/**
	 * Method: gotoLocationEnable
	 * Inizializza il sistema per l'inserimento delle coordinate da ricercare
	 */
	gotoLocationEnable: function(){
		if(!this.gotoLocWin){
			this.gotoLocWin = new TolomeoExt.ToloGotoLocationWindowExt({projectionCrs: this.projectionCrs, projectionCode: this.getProjectionCode(), id:'gotoLoc',closable: true,closeAction: 'hide',iconCls: 'iconGotoPosition'});
			this.gotoLocWin.on('afterlayout',
				function(){
					this.gotoLocWin.centerTo(this.viewer.getEl());
				},this,{single: true});			
			this.gotoLocWin.on('gotoLocation',
				function(x,y,crs){
					// Nel caso di trasformazione ho bisogno delle giuste librerie
					if(crs && crs!= this.getProjectionCode()){
						this.lazyLoadScript(
							'proj4js',
							function(){ this.gotoPosition(x, y, null, true, crs); },
							function(){Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.gotoLocationEnable.title"), ToloI18n.getMsg("ToloMapAPIExt.gotoLocationEnable.msg", {ProjectionCode:this.getProjectionCode()}), function(){this.gotoLocWin.show();},this);},
							this);			
					} else {
						this.gotoPosition(x, y, null, true, crs);
					}
				}, this);
		}
		this.gotoLocWin.show();
			
	},
	
	/**
	 * Method: updateNoteOnMap
	 * Aggiornamento delle note
	 * @param {} id
	 * @param {} htmlText
	 */
	updateNoteOnMap: function(id,htmlText,lon,lat){
		var noteW = this.createNoteWidget('update',{
			title: ToloI18n.getMsg("ToloMapAPIExt.updateNoteOnMap.title"),
			htmlValue : htmlText,
			popupId: id,
			lon: lon,
			lat: lat
		});
		noteW.show();
	},
	
	/**
	 * Method: insertNoteOnMap
	 * Aggiornamento delle note
	 * @param {} posX
	 * @param {} posY
	 */
	insertNoteOnMap: function(posX,posY){
		var noteW = this.createNoteWidget('insert',{
			title: ToloI18n.getMsg("ToloMapAPIExt.insertNoteOnMap.title"),
			x: posX,
			y: posY
		});
		noteW.show();		
	},
	
	createNoteWidget: function(mode,config){
		var coordinate;
		
		if(mode=='update'){
			coordinate = {x: config.lon, y: config.lat};
		} else {
			var viewPos = this.getViewerPosition();
			coordinate = this.viewer.pluginGetCoordinateFromPixel({x:(config.x-viewPos.x),y:(config.y-viewPos.y)});
		}
		
		var formattedCoords = this.formatCoords(coordinate);
		var thisid = this.apiid;
		
		var cnw = Ext.create('Ext.window.Window', {
			layout: 'fit',
			width: 500,
			title: !config.title ? ToloI18n.getMsg("ToloMapAPIExt.createNoteWidget.title") : config.title,
			height: 250,
			iconCls: (mode=='update' ? 'iconEditNote' : 'iconInsertNote'),
			cls: 'clearCSS',
			modal: true,
			items:[{
		    	xtype: 'htmleditor',
		    	cls: 'clearCSS',
		    	enableAlignments: false,
		    	enableFont: false,
		    	enableLinks: true,
		    	enableSourceEdit: false,
		    	value: !config.htmlValue ? '' : config.htmlValue,
		    	listeners: {
	    			change: function(htlmcontrol, newval, oldval, eopts) {
	    				Ext.getCmp(thisid + '-btnOkInsNota').setDisabled(newval=="");
		    		},
		    		render: {
		    			fn: function(){
		    				this.getToolbar().add('-');
		    				this.getToolbar().add({
		    					tooltip: ToloI18n.getMsg("ToloMapAPIExt.createNoteWidget.tooltip"),
		    					iconCls : 'iconAddLocation',
		    					handler : function(){
		    						cnw.down('htmleditor').setValue(cnw.down('htmleditor').getValue() + "<hr noshade>" + formattedCoords.x + " - " + formattedCoords.y );
		    						Ext.getCmp(thisid + '-btnOkInsNota').setDisabled(false);
		    					}
		    				});
		    			}		    			
		    		}
		    	}
			}],
			buttons: [
		          { text: ToloI18n.getMsg("ToloMapAPIExt.createNoteWidget.btnOK"),
		        	id: thisid + '-btnOkInsNota',
		        	disabled: true,
		        	listeners: {
		        		click: function() {
		        			var text = cnw.down('htmleditor').getValue();
			        		if(mode=='update'){			   
			        			this.viewer.pluginUpdatePopup(config.popupId,text);
			        			cnw.close();
			        		} else {
								//var viewPos = this.getViewerPosition(); 
								//var coordinate = this.viewer.pluginGetCoordinateFromPixel({x:(config.x-viewPos.x),y:(config.y-viewPos.y)}); 
								this.viewer.pluginAddPopup(coordinate.x,coordinate.y,text,false,true);
								cnw.close();
			        		}
			        	},
			        	scope: this
			         }
		          },
		          {  
		          	 text: ToloI18n.getMsg("ToloMapAPIExt.createNoteWidget.btnAnnulla"),
		        	 handler: function () { this.up('.window').close(); }
		          }
		    ],
		    listeners : {
	        	show : {
	        		fn :  function(){		   		
	        			Ext.defer(function(){
	        				cnw.down('htmleditor').focus();
	        			},200);
	        			
	        		}
	        	}
	        }
		});
		
		return cnw;
	},
	
	releaseLocationEnable: function(posX,posY,crs){	
		var f = function(){
			var viewPos = this.getViewerPosition(); 
			var coordinate = this.viewer.pluginGetCoordinateFromPixel({x:(posX-viewPos.x),y:(posY-viewPos.y)}); 
			this.releaseCoordinate(coordinate.x,coordinate.y,crs); 
		}
		if(crs == this.getProjectionCode()){
			f.call(this);
		}else{
			this.lazyLoadScript(
				'proj4js',
				f,
				function(){Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.releaseLocationEnable.title"), ToloI18n.getMsg("ToloButtonPanelExt.mnuGuida.text", {ProjectionCode: this.getProjectionCode()}),function(){this.contextMenu.setCrsSelected(this.getProjectionCode());f.call(this)},this);},
				this);
		}
	},
	
	releaseStreetviewEnable: function(posX,posY){
		
		var crs = "EPSG:4326";
		
		var f = function(){
			var viewPos = this.getViewerPosition(); 
			var coordinate = this.viewer.pluginGetCoordinateFromPixel({x:(posX-viewPos.x),y:(posY-viewPos.y)});
			// Messa solamente per assicurarmi che la proiezione attuale sia già stata caricata
			var currProj = new TolomeoExt.Projection(this.getProjectionCode());	
			
			if(!this.svWin){
			
				// da mettere afterrender altrimenti api non esiste
				this.svPanel = new TolomeoExt.ToloStreetviewViewerPanel({
					viewer: this.viewer
				});
	
				this.svWin = new Ext.Window({
					cls: 'clsStreetViewWindow',
					height: 400,
					width: 500,
					collapsible: true,
					maximizable: true,
					layout: 'fit',
					items: [this.svPanel],
					closable: true,
					closeAction: 'hide',
					cls: 'clearCSS',
					listeners: {					
						hide: {
							fn: function () {
								this.viewer.pluginStreetViewDeactivate();
							},
						  	scope: this
						}
					}
				});
				
				this.svWin.on('afterlayout',
					function(){
						this.setStreetviewPosition(coordinate.x,coordinate.y,crs);
					},this,{single: true});			
					
			} else {
				this.setStreetviewPosition(coordinate.x,coordinate.y,crs);
			}
			
			this.svWin.show();		
			this.svWin.setPosition(this.viewer.getPosition());
			this.viewer.pluginStreetViewActivate();
		}
		
		if(crs == this.getProjectionCode()){
			f.call(this);
		}else{
			this.lazyLoadScript(
				'proj4js',
				f,
				function(){Ext.Msg.alert(ToloI18n.getMsg("ToloMapAPIExt.releaseStreetviewEnable.title"), ToloI18n.getMsg("ToloMapAPIExt.releaseStreetviewEnable.msg", {ProjectionCode:this.getProjectionCode()}));},
				this);
		}
			
	},
	
	/**
	 * Method: setStreetviewPosition
	 * rilascia un popup sul viewer con le coordinate nel sistema di riferimento scelto
	 *
	 * Parameters:
	 * mousexy - {Point} posizione del mouse
     * coordsxy - {Point} posizione nel sistema di riferimento base
	 * crs - {String} Codice EPSG del sistema in cui si vogliono le coordinate (Es. EPSG:26591)
	 */
	setStreetviewPosition: function(coordX,coordY,crs){				

		var currProj = new TolomeoExt.Projection(this.getProjectionCode());	
		var currPoint = new Point(coordX,coordY);
		var currReproj = currProj;

		if(crs!= this.getProjectionCode() && TolomeoExt.lazyLoad.checkLoad('proj4js')){
			currReproj = new TolomeoExt.Projection(crs);
			currPoint = TolomeoExt.Projection.transform(currPoint.clone(),currProj,currReproj);
		}
		
		this.svPanel.setViewPosition(currPoint.x,currPoint.y);
			
	},	
	
	/**
	 * Method: releaseCoordinate
	 * rilascia un popup sul viewer con le coordinate nel sistema di riferimento scelto
	 *
	 * Parameters:
	 * coordX - Coordinata x nel sistema di riferimento indicato
     * coordY - Coordinata y nel sistema di riferimento indicato
	 * srid - {String} Codice EPSG del sistema in cui si vogliono le coordinate (Es. EPSG:26591)
	 */
	releaseCoordinate: function(coordX,coordY,srid){				
		
		var crsCode = srid?srid:this.getProjectionCode();
		var currCrsCode = this.getProjectionCode();
		var currProj = new TolomeoExt.Projection(currCrsCode);
		var reprojSrs = this.projectionCrs;		
		var currPoint = new Point(coordX,coordY);
		var currReproj = currProj;

		if(crsCode!= this.getProjectionCode() && TolomeoExt.lazyLoad.checkLoad('proj4js')){
			currReproj = new TolomeoExt.Projection(crsCode);
			currPoint = TolomeoExt.Projection.transform(currPoint.clone(),currProj,currReproj);
			currCrsCode = crsCode;
		}
		
		var currDescr = currReproj.getTitle();
		if(reprojSrs[currCrsCode]){ 
			if (reprojSrs[currCrsCode].precision){
				currPoint.round(reprojSrs[currCrsCode].precision);
			}
			if(reprojSrs[currCrsCode].description){
				currDescr = reprojSrs[currCrsCode].description ;
			}
		}
		var units = currReproj.getUnits()? " [" + currReproj.getUnits() + "]" : "";

		var htmlText = "<div style='font: 11px tahoma,arial,helvetica,sans-serif;'><b><u>" + currCrsCode + "</u></b><br><b>" + currDescr + units + "</b><br>" + currPoint.toString()+"</div>";
		
		this.addPopup(coordX,coordY,htmlText,false,false);
			
	},	
	
	/**
	 * Method: getViewPosition
	 * Restituisce un oggetto con le proprieta x e y che rappresentano la posizione del viewer	
	 */
	getViewerPosition: function(){
		if (this.viewer) {
			var viewerPos = this.viewer.getPosition();
			return {x:viewerPos[0],y:viewerPos[1]};
		}
		return {x:0,y:0};
	},
	
	/**
	 * Method: getProjectionCode
	 * @return {String} restituisce il codice EPSG del sistema di riferimento
	 */
	getProjectionCode: function(){
		return this.viewer.pluginGetProjectionCode();
	},
	
	/**
	 * Method: reprojectToCurrentCrs
	 * Metodo per la riproiezione di un punto con un certo sistemm di riferimento nel sistema di riferimento attuale
	 *
	 * Parameters:
	 * point - {Point} punto con le coordinate x e y
     * sourceSrid - {String} Codice EPSG del sistema in cui si vogliono le coordinate (Es. EPSG:26591)
	 */
	reprojectToCurrentCrs: function(point,sourceSrid){
		var crsCode = sourceSrid?sourceSrid:this.getProjectionCode();
		var currCrsCode = this.getProjectionCode();
		var currProj = new TolomeoExt.Projection(currCrsCode);	
		var currPoint = new Point(point.x,point.y);
		var currReproj = currProj;

		if(crsCode!= currCrsCode && TolomeoExt.lazyLoad.checkLoad('proj4js')){
			currReproj = new TolomeoExt.Projection(crsCode);
			currPoint = TolomeoExt.Projection.transform(currPoint.clone(),currReproj,currProj);			
		}
		
		return currPoint;		
	},

	/**
	 * Method: lazyLoadScript
	 * Metodo per i caricamento onDemand degli script. Durante il caricamento mette il sistema onBusy
	 *
	 * Parameters:
	 * jsKeys - {String/Array} Chiave o array di chiavi definite nel file toloLazyLoad per il caricamento in sequenza degli script correlati
     * onLoad - {Function} Funzione da chiamare quando lo script è caricato
	 * onFail - {Function} Funzione da chiamare quando non si riesce a recuperare lo script
	 * scope - {Object} Ambito della chiamata delle funzioni	 
	 */
	lazyLoadScript: function (jsKeys,onLoad,onFail,scope){
		
		var jsKeysArr = [];
		
		if(jsKeys instanceof Array){
			jsKeysArr = jsKeys;
		}else{
			jsKeysArr.push(jsKeys);	
		}
										
		if(jsKeysArr.length == 0) return;
		
		var me = this;
		
		if(jsKeysArr.length > 1) {
	        var first = jsKeysArr.shift();
	        me.lazyLoadScript(first,
	                      function() { me.lazyLoadScript(jsKeysArr, onLoad, onFail, scope); },
	                      onFail,
	                      scope);
	        return;
	    }
	    
	    var jsKey = jsKeysArr[0];
		
		if(TolomeoExt.lazyLoad.checkLoad(jsKey)){
			if(onLoad){
				onLoad.call(scope);
			}
		}else{
			this.onBusy(true);
			var me = this;
			TolomeoExt.lazyLoad.get(
				jsKey,
				function(){
					this.onBusy(true);
					if(onLoad){
						onLoad.call(scope);
					}
				},
				function(){
					this.onBusy(true);
					if(onFail){
						onFail.call(scope);
					}
				}
				,this);
		}
	},
	// AutoIdentify - FINE
	
	generateCustomInfo : function(helpInfo){				
		
		var infoItems = [];
		
		for(var i = 0; i < helpInfo.infoList.length; i++){
			
			var info = helpInfo.infoList[i];
			var infoItem;
			
			if(info.framed){			
				infoItem = {
					title: info.title,    				
    				autoScroll: false,    				
    				items: [{
						xtype : 'box',												
						autoEl : {
							tag : 'iframe',
							style : 'border-width: 0px',
							src : (info.url ? info.url : 'about:blank')
						}
					}]
					
					//oppure
					//html = '<iframe width="100%" height="100%" frameborder="0" src="' + (info.url ? info.url : 'about:blank') + '"></iframe>';
				}	
			} else {								
				infoItem = {
					title: info.title,
					loader: {
						url: (info.url ? info.url : 'about:blank'),
						autoLoad: true
					}					 	
				}
			}
			
			infoItems.push(infoItem);
		}
		
		this.customInfoWin = new Ext.Window({
			
			title: helpInfo.mainTitle,
			bodyStyle: 'padding: 0px',
			cls: 'clearCSS',
			width: 550,
			height: 450,			
			modal: true,
			closeAction: 'hide',
			constrain: true,
			layout: 'fit',
			buttons: [{
	        	text: ToloI18n.getMsg("ToloMapAPIExt.generateCustomInfo.btnChiudi"),
	       		listeners: {click: {fn: function() {
	       			this.customInfoWin.hide();
	       		},scope: this}}	       		
	        }],
	        items : {
	        	xtype : 'tabpanel',
	        	activeItem : 0,
	        	minTabWidth : 120,
    			tabWidth    : 135,
    			enableTabScroll: true,
    			border: false,
    			defaults: {
    				xtype: 'panel',
    				layout: 'fit',
    				autoScroll: true
    			},
    			items: infoItems
	        }
		});
				
	},
	
	showCustomInfo : function(helpInfo){
		if(!this.customInfoWin){
			this.generateCustomInfo(helpInfo)
		}
		this.customInfoWin.show();
	},
	
	showGuide: function(url){
		window.open(url);
	},
	
	showFaq: function(url){
		window.open(url);
	},
	
	regeneratePage: function(){
		window.location.reload(true);
	},
	
	mailToAdmin : function(to,subject){
		
		var url = 'mailto:' + to;
    	var subject = subject ? subject : "Tolomeo";
    	var body = "";        	
    	body += "User Agent : " + navigator.userAgent;
    	body += "\n\r";
    	body += "Url : " + location.href;
    	body += "\n\r";
    	body += "Versione Tolomeo : " + TolomeoExt.Vars.TOLOMEOVersion;
    	body += "\n\r";
    	body += "SIT core : " + this.paramsJS.sitCoreVersion;
    	body += "\n\r";
		body += "ExtJS : " + Ext.getVersion();
		body += "\n\r";
		body += "OpenLayers : " + OpenLayers.VERSION_NUMBER;
    	body += "\n\r";        	
    	body += "----------------------------------------";
    	body += "\n\r";        	
    	body += "Problema : ";
    	
    	url = Ext.String.urlAppend(url,"subject=" + subject);
    	url = Ext.String.urlAppend(url,"body=" + escape(body)); 
    	
    	window.open(url);
	},
	
	formatCoords : function (coords,crsCode){
		
		var formatter = Ext.util.Format;		
		var currCrsCode = !crsCode? this.getProjectionCode() : crsCode;
		var pattern = '0,000';
		var reprojSrs = this.projectionCrs;
		
		if(reprojSrs[currCrsCode]){ 
			if (reprojSrs[currCrsCode].precision){
				for(var i = 0; i < reprojSrs[currCrsCode].precision; i++){
					if(i == 0) pattern += '.';
					pattern += '0';
				}
			}
        } 
        
        return {
        	x: formatter.number(coords.x,pattern),        
        	y: formatter.number(coords.y,pattern)
        }
	},
	
	addLayerToQGis : function(catIdx, layIdx){				
		if (catIdx && layIdx){			
			
			var mappa = this.paramsJS.mappe.mappaList[0];
			var currCat = this.TOCPanel.tocInfo.getCategoryInfo(catIdx);
			var currLayer =  currCat.layers[layIdx];
			
			var currCatPreset = this.TOCPanel.tocInfo.getCategoryPresetInfo(catIdx);
			var currLayerPreset =  currCatPreset.layerList[layIdx];
			
			var server = this.paramsJS.getServer(currLayerPreset.serverID, mappa);
			
			if (server) {
				var url = server.url;	       
				var layer = currLayerPreset.name;
				var crs = this.paramsJS.mappe.SRID;
				var descr = currLayer.descr;
				//Ext.Msg.alert('Parametri','descrizione = ' + descr + '<br>url = ' + url + '<br>layer = ' + layer + '<br>crs = ' + crs);
	       		JQ.AddWMSLayer(descr,url,layer,'image/png',crs);	       		
			}	
							
		}
			
	},
	
	/**
	 * Method: addRouting
	 * Sulla mappa e' possibile evidenziare dei tracciati, nel caso in cui si richieda il calcolo di un percorso.
	 * Questa funzione consente di evidenziare il tracciato, di aggiornare di conseguenza la mappa e di fare le altre azioni necessarie.
	 * L'attuale implementazione prevede che un solo oggetto possa essere evidenziato, quindi ogni nuovo va a sostituirsi a quello eventualmente presente.
	 *
	 * Parameters:
	 * geoms - {JSGeometryArray o JSGeometry} oggetto da evidenziare se passato un JSGeometryArray viene utilizzato il primo.
	 * bMulti - {boolean} se non definito o false non è consentita la presenza di più di un oggetto, se True è consentita.
	 */
	addRouting: function(routeResponse, bMulti)
	{
		if (!bMulti) this.routingCorrente.clear();
		
		this.routingCorrente.add(routeResponse.geometry);
		
		if (this.viewer != null) {
			this.viewer.pluginAddRouting(routeResponse, bMulti);
			//this.viewer.pluginAddRouting(this.routingCorrente, bMulti);
			
			// Il loop parte volutamente da 1 per escludere la prima istruzione, il cui punto di partenza coincide con lo start point
			/*for (var i = 1; i < routeResponse.instructions.length; i++) {
				this.viewer.pluginAddInstruction(routeResponse.instructions[i].geometry, { tooltip: routeResponse.instructions[i].textInstruction });
			}*/
		}
	},
	
	/**
	 * Method: clearRouting
	 * Svuota il tracciato corrente, 
	 * deselezionando gli oggetti dalla mappa ed effettuando il resto delle operazioni necessarie (come l'aggiornamento delle operazioni di editing, interrogazione etc. possibili)
	 *
	 * Parameters:
	 * bRedraw - {boolean} Se non definito o false non è consentita la presenza di più di un oggetto, se True è consentita.
	 */
	clearRouting: function (bRedraw) {
		this.routingCorrente.clear();
		if (this.viewer.pluginClearRouting(bRedraw)) this.viewer.pluginRefreshMap();
	},
	
	/**
	 * Method: zoomToRouting
	 * Esegue lo zoom al tracciato corente.
	 * 
	 * Parameters:
	 * zoom - {Number} il valore di zoom.
	 * buffer - {Integer} buffer, se valorizzato viene fatto lo zoom aggiungendo il buffer passato
	 */
	zoomToRouting: function(zoom, buffer) {
		this.viewer.pluginZoomToRouting(zoom, buffer || 100);
	},
	
	/**
	 * Method: centerOnRouting
	 * Riposiziona la mappa mettendo al centro il tracciato corrente e mantenendo la scala attuale.
	 */
	centerOnRouting: function(){
		var zoom = this.viewer.pluginGetCurrentZoom();
		this.zoomToRouting(zoom);
	},
	
	/**
	 * Method: addStartRoutingMarker
	 * Aggiunge il marker di inizio tracciato per il routing
	 *
	 * Parameters:
	 * coordX - {} longitudine
	 * coordY - {} latitudine
	 * crsCode - {} sistema di riferimento
	 */
	addStartRoutingMarker: function(coordX, coordY, crsCode) {
		var currPoint = new Point(coordX,coordY);
		
		if (crsCode && this.projectionCrs[crsCode]) {
			var currSrsCode = this.getProjectionCode();
			if (currSrsCode != crsCode) {
				var currProj = new TolomeoExt.Projection(currSrsCode);
				var sourceProj = new TolomeoExt.Projection(crsCode);		
				currPoint = TolomeoExt.Projection.transform(currPoint,sourceProj,currProj);
			}
		}
		
		this.viewer.pluginAddStartRoutingMarker(currPoint.x, currPoint.y); 
	},
	
	/**
	 * Method: addEndRoutingMarker
	 * Aggiunge il marker di inizio tracciato per il routing
	 *
	 * Parameters:
	 * coordX - {} longitudine
	 * coordY - {} latitudine
	 * crsCode - {} sistema di riferimento
	*/
	addEndRoutingMarker: function(coordX, coordY, crsCode) {
		var currPoint = new Point(coordX,coordY);
		
		if (crsCode && this.projectionCrs[crsCode]) {
			var currSrsCode = this.getProjectionCode();
			if (currSrsCode != crsCode) {
				var currProj = new TolomeoExt.Projection(currSrsCode);
				var sourceProj = new TolomeoExt.Projection(crsCode);		
				currPoint = TolomeoExt.Projection.transform(currPoint,sourceProj,currProj);
			}
		}
		
		this.viewer.pluginAddEndRoutingMarker(currPoint.x, currPoint.y); 
	},
	
	/**
	 * Method: addViaRoutingMarker
	 * Aggiunge il marker di inizio tracciato per il routing
	 *
	 * Parameters:
	 * viaId - {} identificativo del punto intermedio
	 * coordX - {} longitudine
	 * coordY - {} latitudine
	 * crsCode - {} sistema di riferimento
	 */
	addViaRoutingMarker: function(viaId, coordX, coordY, crsCode) {
		var currPoint = new Point(coordX,coordY);
		
		if (crsCode && this.projectionCrs[crsCode]) {
			var currSrsCode = this.getProjectionCode();
			if (currSrsCode != crsCode) {
				var currProj = new TolomeoExt.Projection(currSrsCode);
				var sourceProj = new TolomeoExt.Projection(crsCode);		
				currPoint = TolomeoExt.Projection.transform(currPoint,sourceProj,currProj);
			}
		}
		
		this.viewer.pluginAddViaRoutingMarker(viaId, currPoint.x, currPoint.y); 
	},
	
	/**
	 * Method: setViaRoutingMarkers
	 * Imposta tutti i marker di tappa intermedia per il routing
	 *
	 * Parameters:
	 * viaPoints - {Array[ToloOLSVertex]} vertici intermedi
	 * crsCode - {} sistema di riferimento
	*/
	setViaRoutingMarkers: function(viaPoints, crsCode) {
		this.viewer.pluginClearViaRoutingMarkers();
		
		for (var i = 0; i < viaPoints.length; i++) {
			var	point = viaPoints[i].point;
			
			this.addViaRoutingMarker(viaPoints[i].id, point.x, point.y, crsCode);
		}
	},
	
	/**
	 * Method: setViaRoutingMarkers
	 * Restituisce il nome corretto aggiungendo il suffisso se presente
	 *
	 * Parameters:
	 * baseName - {String} nome base del parametro 
	*/
	_getPermalinkParameterName: function(baseName){
		return this.permalinkParameterSuffix ? (baseName + this.permalinkParameterSuffix) : baseName;			
		
	},
	
	
	/* Servizi di mapping esterni */
	/**
	 * @method scaleToZoomLevel
	 * 
	 * Converte una scala (scaledenom) in zoomLevel
	 * 
	 * @pparam {Number} scale scala
	 * @return {Number} zoomLevel corrispondente
	 */
	scaleToZoomLevel: function(scale) {
		
		if (scale>this.zoomLevelConvTable[0].scaledenom) {
			return 0;
		}
		
		for (var i=0; i<this.zoomLevelConvTable.length; i++) {
			 if (this.zoomLevelConvTable[i].scaledenom < scale) {
				 var distUp   = this.zoomLevelConvTable[i-1].scaledenom - scale;
				 var distDown = scale - this.zoomLevelConvTable[i].scaledenom;
				 if (distUp < distDown) {
					 return i-1;
				 } else {
					 return i;
				 }
			 }
		}
		return this.zoomLevelConvTable.length -1;
		
	},
	
	/**
	 * @method apriMappaHere
	 * 
	 * Apre una mappa del servizio Here nella stessa posizione attuale e con il livello di zoom, tra quelli supportati dal servizio, 
	 * più vicino possibile a quello attuale.
	 * 
	 * @pparam {Number} tipo tipo di mappa da aprire
	 * 
	 */
	apriMappaHere: function(tipo) {
		
		var crs = "EPSG:4326";
		var urlTmpl = "https://www.here.com?map=%lat%,%lon%,%zoomlev%,%tipo%";
		urlTmpl = urlTmpl.replace("%tipo%", tipo);
		
		var url = this.urlMappaDaTemplate(urlTmpl, crs);
		
		window.open(url, "_blank");
		
	},
	
	/**
	 * @method apriMappaBing
	 * 
	 * Apre una mappa del servizio Bing nella stessa posizione attuale e con il livello di zoom, tra quelli supportati dal servizio, 
	 * più vicino possibile a quello attuale.
	 * 
	 * @pparam {Number} tipo tipo di mappa da aprire
	 * @pparam {Number} dir direzione per mappe oblique
	 * 
	 */
	apriMappaBing: function(tipo, dir) {
		
		var crs = "EPSG:4326";
		var urlTmpl = "http://www.bing.com/maps/default.aspx?cp=%lat%~%lon%&lvl=%zoomlev%&style=%tipo%&dir=%dir%";
		urlTmpl = urlTmpl.replace("%tipo%", tipo);
		urlTmpl = urlTmpl.replace("%dir%",  dir);
		
		var url = this.urlMappaDaTemplate(urlTmpl, crs);
		
		window.open(url, "_blank");
		
		//https://www.here.com/?map=43.88491,11.09798,20,satellite
		//https://www.here.com/?map=43.88491,11.09798,20,normal
		//https://www.here.com/?map=43.88491,11.09798,20,terrain
		
	},
	

	/**
	 * @method apriMappaOSM
	 * 
	 * Apre una mappa del servizio Openstreetmap nella stessa posizione attuale e con il livello di zoom, tra quelli supportati dal servizio, 
	 * più vicino possibile a quello attuale.
	 * 
	 */
	apriMappaOSM: function() {
		
		var crs = "EPSG:4326";
		var urlTmpl = "http://www.openstreetmap.org/#map=%zoomlev%/%lat%/%lon%";
		
		var url = this.urlMappaDaTemplate(urlTmpl, crs);
		
		window.open(url, "_blank");
		
		//https://www.here.com/?map=43.88491,11.09798,20,satellite
		//https://www.here.com/?map=43.88491,11.09798,20,normal
		//https://www.here.com/?map=43.88491,11.09798,20,terrain
		
	},
	
	/**
	 * @method apriMappaGoogle
	 * 
	 * Apre una mappa del servizio Google nella stessa posizione attuale e con il livello di zoom, tra quelli supportati dal servizio, 
	 * più vicino possibile a quello attuale.
	 * 
	 * @pparam {Number} tipo tipo di mappa da aprire
	 * @pparam {boolean} bclassic indica se aprire la viusualizzazione "classic"
	 * 
	 */
	apriMappaGoogle: function(tipo, bclassic) {
		
		var crs = "EPSG:4326";
		//
		var urlTmpl = "";
		if (bclassic) {
			urlTmpl = "https://www.google.it/lochp?ll=%lat%,%lon%&z=%zoomlev%&t=%tipo%";
		} else {
			urlTmpl = "https://www.google.it/maps?ll=%lat%,%lon%&z=%zoomlev%&t=%tipo%";
			
		/*	var urlTmpl = "https://www.google.it/maps/@%lat%,%lon%,%zoomlev%z";
			urlTmpl += ',20y,%dir%h,%incl%t/data=!3m1!1e3';
			urlTmpl = urlTmpl.replace("%dir%",  dir);
			urlTmpl = urlTmpl.replace("%incl%",  incl);*/
		}
		urlTmpl = urlTmpl.replace("%tipo%",  tipo);
		var url = this.urlMappaDaTemplate(urlTmpl, crs);

		window.open(url, "_blank");
		
		//https://www.here.com/?map=43.88491,11.09798,20,satellite
		//https://www.here.com/?map=43.88491,11.09798,20,normal
		//https://www.here.com/?map=43.88491,11.09798,20,terrain
		
	},
	
	
	/**
	 * @method urlMappaDaTemplate
	 * 
	 * Sostituisce nel template della url i valori relativi alla paosiozne ed al livello di zoom correnti
	 * 
	 * @pparam {Number} urlTmpl tipo di mappa da aprire
	 * @pparam {boolean} crs indica se aprire la viusualizzazione "classic"
	 * 
	 */
	urlMappaDaTemplate: function(urlTmpl, crs) {
	
		//var crs = "EPSG:4326";
		//var urlTmpl = "https://www.here.com/?map=%lat%,%lon%,%zoomlev%,%tipo%";
		//var url = urlTmpl.replace("%tipo%", tipo);
		
		// Sostituzione zoomLevel
		var zoomLev = this.scaleToZoomLevel(this.viewer.pluginGetCurrentZoom());
		var url = urlTmpl.replace("%zoomlev%", zoomLev);
		
		// Sostituzione longitudine e latitudine centro mappa
		var coordX = this.viewer.pluginGetCurrentX();
		var coordY = this.viewer.pluginGetCurrentY();
		var currPoint = new Point(coordX,coordY);
		var currProj = new TolomeoExt.Projection(this.getProjectionCode());	
		
		if(crs!= this.getProjectionCode() && TolomeoExt.lazyLoad.checkLoad('proj4js')){
			currReproj = new TolomeoExt.Projection(crs);
			currPoint = TolomeoExt.Projection.transform(currPoint.clone(),currProj,currReproj);
		}
		
		url = url.replace("%lon%", currPoint.x);
		url = url.replace("%lat%", currPoint.y);
		
		return url;
	},
	
	/**
	 * @method getSelezioneCorrente
	 * 
	 * Recupera l'oggetto selezione corrente
	 * 
	 * @return {JSGeometryArray} Selezione corrente
	 * 
	 */
	getSelezioneCorrente: function() {
		return this.selezioneCorrente;
	},
	
	/**
	 * @method getEvidenziazioneCorrente
	 * 
	 * Recupera l'oggetto evidenziazione corrente
	 * 
	 * @return {JSGeometryArray} Evidenziazione corrente
	 * 
	 */
	getEvidenziazioneCorrente: function() {
		return this.evidenziazioneCorrente;
	}
	
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * @class TolomeoExt.ToloPointFromRefPanelExt
 * @extends Ext.Window
 * 
 * 
 */
Ext.define('TolomeoExt.ToloPointFromRefPanelExt', {
	
	extend: 'Ext.Window',
	
	/**
	 * @property {Boolean} [closable=false]
	 * 
	 * 
	 */
	closable: false,
	
	/**
	 * @property {Boolean} [bodyBorder=false]
	 * 
	 * 
	 */
	bodyBorder: false,
	
	/**
	 * @property {Boolean} [border=false]
	 * 
	 * 
	 */
	border: false,
	
	/**
	 * @property {Boolean} [frame=true]
	 * 
	 * 
	 */
	frame: true,
	
	/**
	 * @property {Boolean} [resizable=false]
	 * 
	 * 
	 */
	resizable: false,
	
	/**
	 * @property {Boolean} [constraint=true]
	 * 
	 * 
	 */
	constraint: true,
	
	/*
	 * @property {Boolean} [monitorResize=true]
	 * 
	 * 
	 */
	//monitorResize: true,
	
	/**
	 * @property {Number} [width=280]
	 * 
	 * 
	 */
	width: 280,
	
	/**
	 * @property {Boolean} [collapsible=true]
	 * 
	 * 
	 */
	collapsible: true,
	
	/*
	 * @property {String} [bodyStyle='background-color:white;']
	 * 
	 * 
	 */
	//bodyStyle: 'background-color:white;',
		
	/**
	 * @method initComponent
	 * 
	 * 
	 */
	initComponent: function() {
		
		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		this.callParent(arguments);
		this.title = ToloI18n.getMsg("ToloPointFromRefPanelExt.title");
		this.addEvents('pressSetDistance');
		this.notifyDistanceSetting = function(){		
			var distance = this.getCmp(this.getId()+"-distanceFromRef").getValue(); //this.pfr.find("name","distanceFromRef")[0].getValue();
		    distance = (""+distance).replace(",",".");			
		    if (!distance || isNaN(distance)) {
				Ext.Msg.alert(ToloI18n.getMsg("ToloPointFromRefPanelExt.alert.title"),ToloI18n.getMsg("ToloPointFromRefPanelExt.alert.msg"));
				return;
			}				    
			this.fireEvent('pressSetDistance', distance);
		}
		
		this.selectAndFocus = function(){			
			this.getCmp(this.getId()+"-distanceFromRef").focus().selectText();    //this.pfr.find("name","distanceFromRef")[0].focus().selectText();
		}
		this.helpWin;
		this.pfr = new Ext.FormPanel({
	        labelWidth: 110, // label settings here cascade unless overridden
	        url:'#',
	        frame:true,
	        title: '',
	      //  bodyStyle:'padding:5px 5px 0',
	        
	      	bodyStyle: 'padding:2px;',
	       // width: 350,
	      	
	        items: [{
	            xtype: 'numberfield',	            	
                fieldLabel: ToloI18n.getMsg("ToloPointFromRefPanelExt.fldDist"),
                id: this.getId()+'-distanceFromRef',
	            name: 'distanceFromRef',
	            allowBlank: true,
	            allowDecimals: true,
	            allowNegative: false
		            
	        }
	        /*
	        ,{
	        	xtype: 'displayfield', 
	        	fieldLabel: 'Distanza attuale', 
	        	value: 'prova',
	        	name: 'currenteDistanceFromRef',
	        	id: 'currentDistanceFromRef'
	        }
	        */],
	        buttons: [{
	            text: 'Imposta',
	            type: 'submit',
	            handler: this.notifyDistanceSetting,
				scope: this
	        },{
	        	minWidth: 20,
	            text: ' ? ',
	            type: 'submit',
	            handler:  function(){
		        // create the window on the first click and reuse on subsequent clicks
		        if(!this.helpWin){
		            this.helpWin = new Ext.Window({
		                layout:'fit',
		                width:500,
		                autoHeight: true,
		                title: ToloI18n.getMsg("ToloPointFromRefPanelExt.helpWin.title"),
		                //plain: true,
		                		
		                items: new Ext.Panel({
		                    deferredRender:false,
		                    border:false,
		                    html:ToloI18n.getMsg("ToloPointFromRefPanelExt.helpWin.html")		                    	 	                    	
		                }),		
		                buttons: [{
		                    text: ToloI18n.getMsg("ToloPointFromRefPanelExt.helpWin.btnChiudi"),
		                    handler: function(){
		                        this.helpWin.hide();
		                    },
		                    scope: this
		                }]
		            });
		        }
		        this.helpWin.show(this);
		    },
				scope: this
	        }],
	        
	        keys: [{
	        	key: [Ext.EventObject.ENTER], 
             	handler: this.notifyDistanceSetting,
                scope: this
             }]  	        
	    });
			    	    
		this.add(this.pfr);
		this.doLayout();
	},
	   
	/**
	 * @method show
	 * Mostra il pannello CAD e lo rimette nella posizione 0,0
	 * 
	 */ 
    show: function () {
		this.setPosition(0,0);
		this.callParent(arguments);
		Ext.Function.defer(this.selectAndFocus,200,this);
		//this.displayDistance(0);
	},

	/**
	 * @method hide
	 * Nasconde il pannello CAD e e resetta il comando
	 * 
	 */ 
	hide: function () {
		this.getCmp(this.getId()+"-distanceFromRef").setValue(""); 
		//this.pfr.find("name","distanceFromRef")[0].setValue("");
		this.callParent(arguments);
		//this.displayDistance(0);
	},
	
/*
	displayDistance: function (distance) {
		Ext.getCmp('currentDistanceFromRef').setValue(Math.round(distance*100)/100);
		this.setVisible(true);
	},	
*/	

	/**
	 * @method bindToViewerPanel
	 * 
	 * 
	 * @param {Object} viewer
	 * 
	 * 
	 */ 
	bindToViewerPanel: function(viewer) {
		if (viewer!=null) {
			// Registrazione in viewerPanel
			viewer.on('onDrawFirstPointFromRef', this.show, this );
			viewer.on('onDigitizePointFromRefEnd', this.hide, this);
			//viewer.on('onDigitizePointFromRefCallback', function(){this.clear();this.hide();}, this);
			//viewer.on('onDrawDistanceFromRefChange', this.displayDistance, this);
		}
	}
			
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * 
 * @class TolomeoExt.ToloCADPanelExt
 * @extends Ext.Window
 * 
 * 
 */
Ext.define('TolomeoExt.ToloCADPanelExt', {
	extend: 'Ext.Window',

	/** 
	 * @property {Boolean} [closable=false]
	 * 
	 * 
	 */
	closable: false,
	
	/** 
	 * @property {Boolean} [bodyBorder=false]
	 * 
	 * 
	 */
	bodyBorder: false,
	
	/** 
	 * @property {Boolean} [border=false]
	 * 
	 * 
	 */
	border: false,
	
	/** 
	 * @property {Boolean} [frame=true]
	 * 
	 * 
	 */
	frame: true,
	
	/** 
	 * @property {Boolean} [resizable=false]
	 * 
	 * 
	 */
	resizable: false,
	
	/** 
	 * @property {Boolean} [constraint=true]
	 * 
	 * 
	 */
	constraint: true,
	
	/*
	 * @property {Boolean} [monitorResize=true]
	 * 
	 * 
	 */
	//monitorResize: true,
	
	/** 
	 * @property {Number} [width=380]
	 * 
	 * 
	 */
	width: 390,
	
	/**
	 * @property {Boolean} [collapsible=true]
	 * 
	 */
	collapsible: true,	
		
	/**
	 * @method initComponent
	 * Create a new TolomeoExt.ToloCADPanelExt
	 * 
	 */	
	initComponent: function() {
		
		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		this.callParent(arguments);
			
		this.title = ToloI18n.getMsg("ToloCADPanelExt.title");
		var me = this;
		// 
		this.addEvents('pressSetCommand');
		this.addEvents('changeAngleSetting');	
		this.addEvents('pressDeleteFirstLine');
		
		/*
		 * @method notifyCommandSetting
		 * Notifica l'impostazione di un comando CAD
		 * 
		 */ 
		this.notifyCommandSetting = function(){		
			var commandCmp = Ext.getCmp(this.getId()+'-command');
			//var commandCmp = this.cad.find("name","command")[0];
			this.fireEvent('pressSetCommand', "@" + commandCmp.getValue());
			commandCmp.setValue("");
			this.selectAndFocus();
		}
		
		/*
		 * @method notifyAngleSetting
		 * Notifica l'impostazione dell'angolo
		 *
		 * @param {Object} radioGrp
		 * il gruppo di radio button.
		 * 
		 * @param {Object} radio
		 * il radio button.
		 * 
		 */ 
		this.notifyAngleSetting = function(radioGrp,radio){						
			this.fireEvent('changeAngleSetting', radio.getRawValue());	
			this.selectAndFocus();					
		}
		
		/*
		 * @method notifyDeleteFirstLine
		 * Notifica la richiesta di cancellazione della prima linea		
		 * 
		 */ 
		this.notifyDeleteFirstLine = function(){						
			this.fireEvent('pressDeleteFirstLine');
			this.selectAndFocus();						
		}
		
		/*
		 * @method selectAndFocus
		 * Imopsta il focus e seleziona il testo sul input text del comando.	
		 * 
		 */ 
		this.selectAndFocus = function(){
			Ext.getCmp(this.getId()+'-command').focus();
			//this.cad.find("name","command")[0].focus();//.selectText();
		}
		
		this.helpWin;		
		this.cad = Ext.create('Ext.FormPanel',{	        
	        url:'#',
	        frame:true,
	        title: '',
	        //  bodyStyle:'padding:5px 5px 0',	        
	      	//  bodyStyle: 'padding:2px;',
	        //  width: 350,
	      	defaults: {
	      		labelWidth: 120
	      	},	      	
		    items: [{		    	
            	anchor: '98%',
	            xtype: 'textfield',	
	            labelSeparator : ' ',            	
                fieldLabel: ToloI18n.getMsg("ToloCADPanelExt.fldProssimoPunto"),
                id: this.getId()+'-command',
	            name: 'command',
	            maskRe:/\d|<|,|\.|\-/,	
	            regex: /^((<(\-)?\d+(\.\d+)?)|(,(\-)?\d+(\.\d+)?)|((\-)?\d+(\.\d+)?((,|<)((\-)?\d+(\.\d+)?)?)?))$/,
	            allowBlank: true,
	            allowDecimals: true,
	            allowNegative: false,
	            listeners: {
	                specialkey: function(field, e){
	                    if (e.getKey() == e.ENTER) {
	                    	this.notifyCommandSetting();
	                    }
	                },
	                scope: this
	            }
		    },{
		    	xtype: 'radiogroup',
	            fieldLabel: ToloI18n.getMsg("ToloCADPanelExt.fldRelativoA"),
	            listeners: {change:{fn:this.notifyAngleSetting,scope:this}},
	            items: [{
	                checked: true,
	                boxLabel: ToloI18n.getMsg("ToloCADPanelExt.fldRelativoA.latoprec"),
	                name: 'relativeAngle',
	                inputValue: '1'
	            },{		                
	                boxLabel: ToloI18n.getMsg("ToloCADPanelExt.fldRelativoA.orizzontale"),
	                name: 'relativeAngle',
	                inputValue: '0'
	            }]		           
		    }],
	        buttons: [{
	            text: ToloI18n.getMsg("ToloCADPanelExt.btnImposta"),
	            type: 'submit',
	            handler: this.notifyCommandSetting,
				scope: this
	        },{
	            text: ToloI18n.getMsg("ToloCADPanelExt.btnCancellaPrimaLinea"),
	            type: 'submit',
	            handler: this.notifyDeleteFirstLine,
				scope: this
	        }],
	        
	        keys: [{
	        	key: [Ext.EventObject.ENTER], 
             	handler: this.notifyCommandSetting,
                scope: this
             }]  	        
	    });
			    	    
		this.add(this.cad);
		this.tools = [{
			id : 'help', // 6
			handler : function() {
			// create the window on the first click and reuse on subsequent clicks
		        if(!this.helpWin){
		            this.helpWin = Ext.create('Ext.Window',{
		                layout:'fit',
		                width:500,
		                height: 500,		                
		                title: ToloI18n.getMsg("ToloCADPanelExt.winHelp.title"),	
		                closeAction: 'hide',
		                		
		                items: Ext.create('Ext.Panel',{
		                    deferredRender:false,
		                    autoScroll: true,		                    		                    
		                    bodyStyle: 'padding:10px;font-size:12px;line-height:150%',
		    				frame: false,
		    				border: false,
		    				plain: true,
		                    html: ToloI18n.getMsg("ToloCADPanelExt.winHelp.html")
		                }),		
		                buttons: [{
		                    text: ToloI18n.getMsg("ToloCADPanelExt.winHelp.btnChiudi"),
		                    handler: function(){
		                        this.helpWin.hide();
		                    },
		                    scope: this
		                }]
		            });
		        }
		        this.helpWin.show(this);
}
}];
		this.doLayout();
	},
		
  /**
	 * @method show
	 * Mostra il pannello CAD e lo rimette nella posizione 0,0
	 * 
	 */ 
    show: function () {		
		this.setPosition(0,0);
		this.callParent(arguments);
		Ext.Function.defer(this.selectAndFocus,200,this);		
	},

	/**
	 * @method hide
	 * Nasconde il pannello CAD e e resetta il comando
	 * 
	 */ 
	hide: function () {	
		Ext.getCmp(this.getId()+'-command').setValue("");
		//this.cad.find("name","command")[0].setValue("");
		this.callParent(arguments);
	},

	
	/**
	 * @method bindToViewerPanel
	 * Imposta i gestori degli eventi di interesse lanciati dal viewer
	 *
	 * @param {Object} viewer
	 * visualizzatore della mappa
	 * 
	 */ 
	bindToViewerPanel: function(viewer) {
		if (viewer!=null) {
			// Registrazione in viewerPanel
			viewer.on('onDrawFirstPointByCAD', this.show, this );
			viewer.on('onDigitizePolygonByCADEnd',this.hide, this);
			viewer.on('onDigitizeLineByCADEnd',this.hide, this);
			viewer.on('onDigitizePointByCADEnd',this.hide, this);
		}
	}
			
});
 /* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * @class TolomeoExt.ToloGotoLocationWindowExt
 * @extends Ext.Window
 * 
 * 
 */
Ext.define('TolomeoExt.ToloGotoLocationWindowExt', {
		
	extend: 'Ext.Window',
	/** 
	 * @property {Boolean} [closable=false]
	 * 
	 * 
	 */
	closable: false,
	
	/** 
	 * @property {Boolean} [bodyBorder=false]
	 * 
	 * 
	 */
	bodyBorder: false,
	
	/** 
	 * @property {Boolean} [border=false]
	 * 
	 * 
	 */
	border: false,
	
	/** 
	 * @property {Boolean} [frame=true]
	 * 
	 * 
	 */
	frame: true,
	
	/** 
	 * @property {Boolean} [resizable=false]
	 * 
	 */
	resizable: false,
	
	/** 
	 * @property {Boolean} [constraint=true]
	 * 
	 */
	constraint: true,
	
	/*
	 * @property {Boolean} [monitorResize=true]
	 * 
	 * 
	 */
	//monitorResize: true,
	
	/** 
	 * @property {Number} [width=370]
	 * 
	 */
	width: 450,
	
	/**
	 * @property {Boolean} [collapsible=false]
	 * 
	 */
	collapsible: false,	
	
	/**
	 * @property {Object} [projectionCrs={}]
	 * 
	 */
	projectionCrs : {},
	
	/**
	 * @property {String} projectionCode
	 * 
	 */
	projectionCode: null,
	
	/*
	 * @property {String} [cls=clearCSS]
	 * 
	 */
	//cls: 'clearCSS',
		
	/**
	 * @method initComponent
	 * Create a new TolomeoExt.ToloGotoLocationWindowExt
	 * 
	 */	
	initComponent: function() {
		
		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		this.callParent(arguments);
		this.title = ToloI18n.getMsg("ToloGotoLocationWindowExt.title");
		this.addEvents('gotoLocation');	
		
		var thisGotoLoc = this;
		
		/**
		 * @method splitValue
		 * Divide i valori su x ed y se entrambi sono stati messi divisi da virgola in x.
		 * 
		 */
		var splitValue = function(){	
		
			var coordXCmp = Ext.getCmp(thisGotoLoc.getId()+"-coordX");  	//this.find("name","coordX")[0];		
			if(coordXCmp.isValid()){
				var xValue = coordXCmp.getValue();			
				if(xValue.indexOf(",") != -1){
					var xy = xValue.split(/\s*,\s*/g);
					var coordYCmp =Ext.getCmp(thisGotoLoc.getId()+"-coordY"); // this.find("name","coordY")[0];
					coordXCmp.setValue(xy[0]);
					coordYCmp.setValue(xy[1]);
					//.replace(/^\s+|\s+$/gm,'');
				}
			}					
		}
		
		var invert = function(){
			
			splitValue.call(thisGotoLoc);
			
			var coordXCmp = Ext.getCmp(thisGotoLoc.getId()+"-coordX");
			var coordYCmp = Ext.getCmp(thisGotoLoc.getId()+"-coordY");			
			
			var xValue = coordXCmp.getValue();
			var yValue = coordYCmp.getValue();			

			coordXCmp.setValue(yValue);
			coordYCmp.setValue(xValue);			
		}
		
		var notifyGotoLocation = function(){
			
			splitValue.call(thisGotoLoc);
			
			var coordXCmp = Ext.getCmp(thisGotoLoc.getId()+"-coordX"); // this.goToLoc.find("name","coordX")[0];
			var coordYCmp = Ext.getCmp(thisGotoLoc.getId()+"-coordY"); //this.goToLoc.find("name","coordY")[0];		
			
			if(!coordXCmp.isValid()){
				Ext.Msg.alert(ToloI18n.getMsg("ToloGotoLocationWindowExt.error.XNonValido.title"),
						ToloI18n.getMsg("ToloGotoLocationWindowExt.error.XNonValido.msg"));
				return;
			}
			
			if(Ext.isEmpty(coordYCmp.getValue())){
				Ext.Msg.alert(ToloI18n.getMsg("ToloGotoLocationWindowExt.error.YAssente.title"),
						ToloI18n.getMsg("ToloGotoLocationWindowExt.error.YAssente.msg"));
				return;
			}
			
			if(!coordYCmp.isValid()){
				Ext.Msg.alert(ToloI18n.getMsg("ToloGotoLocationWindowExt.error.YNonValido.title"),
						ToloI18n.getMsg("ToloGotoLocationWindowExt.error.YNonValido.msg"));
				return;
			}
			
			var xValue = coordXCmp.getValue();
			var yValue = coordYCmp.getValue();			
			var crs = Ext.getCmp(thisGotoLoc.getId()+"-crs").getValue(); //this.goToLoc.find("name","crs")[0].getValue();
			
			this.fireEvent('gotoLocation', xValue, yValue, crs);
			coordXCmp.setValue("");
			coordYCmp.setValue("");
			this.hide();				
		}
						
		var myData = new Array();		      
		      
		for(var i in this.projectionCrs){         
			if(this.projectionCode && this.projectionCode == i) {
				myData.unshift([i,this.projectionCrs[i].description,ToloI18n.getMsg("ToloGotoLocationWindowExt.error.YNonValido.title")]); 
			} else {
				myData.push([i,this.projectionCrs[i].description,'']);            
			}
	    }
	    
	    if(!this.projectionCode) this.projectionCode = myData[0][0];
		  
	    var myStore = new Ext.data.ArrayStore({
	         fields: [
	           'code',
	           'description',
	           'extraInfo'
	         ],
	         data : myData
	    });
    
		this.goToLoc = Ext.create('Ext.form.Panel',{
	        labelWidth: 60, // label settings here cascade unless overridden
	     	labelAlign: 'left',	     	
	        url:'#',
	        frame:true,
	        title: '',
	        //defaultType: 'textfield',
		    items: [{            	
	            xtype: 'label',	
	            html: ToloI18n.getMsg("ToloGotoLocationWindowExt.html")
		    },{
		    	xtype: 'container',
		    	layout: 'hbox',
            	frame: false,	
            	//xtype: 'fieldset',
	            items:[{
	                flex: 1,
                    xtype: 'textfield',
		            padding: '5 5 5 0',
		            labelStyle: 'font-weight: bold;',
		            labelWidth: 60,
		            labelSeparator : ' ',            	
	                fieldLabel: 'X|Lon : ',
	                id: this.getId()+'-coordX',
		            name: 'coordX',
		            maskRe:/\d|,|\.|\-|\+/,	
		            regex: /^(\-|\+)?\d+(\.\d+)?\s*(,\s*(\-|\+)?\d+(\.\d+)?)?$/,
		            allowBlank: false,
		            allowDecimals: true,
		            allowNegative: true,
		            listeners: {blur:  {fn: splitValue, scope: thisGotoLoc}}
	            },{
	                flex: 1,
	                anchor:'95%',
                    xtype: 'textfield',
                    padding: '5 5 5 5',
                    labelStyle: 'font-weight: bold;',
                    labelWidth: 50,
		            labelSeparator : ' ',            	
	                fieldLabel: 'Y|Lat : ',
	                id: this.getId()+'-coordY',
		            name: 'coordY',
		            maskRe:/\d|\.|\-|\+/,	
		            regex: /^(\-|\+)?\d+(\.\d+)?$/,
		            allowBlank: true,
		            allowDecimals: true,
		            allowNegative: true,
		            anchor: '-5'
	           
	            }]
        	},
        	new Ext.form.ComboBox({
		    	labelStyle: 'font-weight: bold;',
		    	labelWidth: 60,
		    	id: this.getId()+'-crs',
		    	name: 'crs',
		        store: myStore,
		        //width: 270,
		        displayField:'code',
		        valueField: 'code',
		        fieldLabel:'CRS',        
		        hideTrigger:false,
				lazyInit: false,
				//typeAhead: true,
			    triggerAction: 'all',
			    lazyRender:true,
			    mode: 'local',
				forceSelection: true,
				autoSelect: true,
				listConfig: {
				    itemTpl: "<b><u>{code}</u></b> {extraInfo}<br>{description}"
				
				},
		        anchor: '-5',
		        value: this.projectionCode
		    })],
	        buttons: [{
	        	text: 'XY > YX',
	            type: 'button',
	            handler: invert,
				scope: this
	        },{
	            text: 'Vai',
	            type: 'submit',
	            handler: notifyGotoLocation,
				scope: this
	        }],
	        
	        keys: [{
	        	key: [Ext.EventObject.ENTER], 
             	handler: notifyGotoLocation,
                scope: this
             }]  	        
	    });
		    	    
		this.add(this.goToLoc);
		this.doLayout();
	},
	
	/**
	 * @method centerTo
	 * Centra rispetto all'elemnto passto (viewer ad esempio)
	 * o rispetto al container se non viene passato l'elemento.
	 * 
	 * @param {Object} el
	 * 
	 * 
	 */	
	centerTo: function(el){
		el = Ext.get(el);                
		if(!el || !el.dom){            
			el = this.container;        
		}				
		var xy = this.getEl().getAlignToXY(el, 'c-c');        
  		this.setPagePosition(xy[0], xy[1]);
	}
					
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloContextMenu
 * @extends Ext.Toolbar
 * 
 * 
 */
Ext.define('TolomeoExt.ToloContextMenu', {
	
	extend: 'Ext.menu.Menu',

	/**
	 * @type {TolomeoExt.ToloMapAPIExt}
	 * Settato automaticamente da bindToApi. 
	 * 
	 */
	api: null,
	
	/** 
	 * @property {Object} paramsJS
	 * 
	 * 
	 */
	paramsJS :null,

	/** 
	 * @property {String} TOLOMEOServer
	 * 
	 * 
	 */
	TOLOMEOServer: null,

	/** 
	 * @property {String} TOLOMEOContext
	 * 
	 * 
	 */
	TOLOMEOContext: null,	

	/** 
	 * @property {String} iconBasePath
	 * 
	 * 
	 */
	iconBasePath:null,
	
	/** 
	 * @property {String} [cls='clearCSS']
	 * 
	 * 
	 */
	cls: 'clearCSS',
	
	/** 
	 * @property {String} crsSelected
	 * 
	 * 
	 */
	crsSelected: null,
	
	/** 
	 * @property {String} projectionCrs
	 * 
	 * 
	 */
	projectionCrs: null,
	
	/**
	 * Metodo di calcolo routing con openls
	 */
	olsMethod: 'Fastest',
	
	/**
	 * @method initComponent
	 * Create a new button toolbar
	 * 
	 */
	initComponent: function() {

		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);

		this.callParent(arguments);
		var thisContextMenu = this;	
		
		if (this.iconBasePath==null) this.iconBasePath =  TolomeoExt.Vars.TOLOMEOServer + TolomeoExt.Vars.TOLOMEOStaticRoot + 'img/icone/16-default/';
		
		//var hide_context_menu = function () { thisContextMenu.hide() }; 
		
		//fixIE10
		//if (Ext.isIE10){this.setWidth(200);}
		
		// necessarie perchè altrimenti il menu non scompare dalla più dalla pagina
		//this.on('show', function () {Ext.getDoc().on('mouseup', hide_context_menu)},this);
		//this.on('hide', function () {Ext.getDoc().un('mouseup', hide_context_menu)},this);		

		this.xEvtPos = 0;
		this.yEvtPos = 0;
		
		// add custom events
		this.addEvents('onGotoLocClickFn');
		this.addEvents('onReleaseLocClickFn');
		this.addEvents('onReleaseStreetviewClickFn');
		this.addEvents('onNotaClickFn');
		
			
		var listenersClick  = {click:  {fn: this.btnClickHandler,  scope: thisContextMenu}};
			
		var notifyReleaseLoc = function(){
			thisContextMenu.fireEvent('onReleaseLocClickFn', thisContextMenu.getXEvtPos(), thisContextMenu.getYEvtPos(), thisContextMenu.crsSelected);
		}
		
		var notifyReleaseStreetview = function(){
			thisContextMenu.fireEvent('onReleaseStreetviewClickFn', thisContextMenu.getXEvtPos(), thisContextMenu.getYEvtPos());
		}

		var notifyNota = function(){
			thisContextMenu.fireEvent('onNotaClickFn', thisContextMenu.getXEvtPos(), thisContextMenu.getYEvtPos());
		}
		
		var onCrsCheck = function(item, checked){
        		thisContextMenu.crsSelected = item.crs;
        		notifyReleaseLoc(item,null);          	
    	}

    	this.add({
			text: ToloI18n.getMsg("ToloContextMenu.nota"),
			icon: this.iconBasePath + 'note.gif',
			handlerBaseName : 'Nota',
			listeners: {click: {fn: notifyNota,  scope: thisContextMenu}}
		});
		
		this.add("-");
		
		this.add({
			text: ToloI18n.getMsg("ToloContextMenu.vaiAPos"),
			icon: this.iconBasePath + 'target.gif',
			handlerBaseName : 'GotoLoc',
			listeners: listenersClick
		});
		
		if(this.projectionCrs){		
			
			var crsItem = [];
			for(var i in this.projectionCrs){
				crsItem.push({
                    text: this.projectionCrs[i].description,
                    id: 'chk_'+ i,
                    crs: i,
                    group: 'crs',                        
                    handlerBaseName : 'ReleaseLoc',
                    xtype: 'menucheckitem',
                    listeners: {click: {fn: onCrsCheck,  scope: thisContextMenu}}
                });
			}
			
			this.add({
				text: ToloI18n.getMsg("ToloContextMenu.rilasciaIndic"),
				id: this.getId() + 'releaseLoc',
				menu: {
					cls: 'clearCSS',
	                items: crsItem
	            },
				icon: this.iconBasePath + 'rilasciaxy.gif',
				handlerBaseName : 'ReleaseLoc',
				listeners: {click: {fn: notifyReleaseLoc,  scope: thisContextMenu}}
			});
			
			//fixIE10
			//if (Ext.isIE10){Ext.getCmp('releaseLoc').menu.setWidth(200);}
			
		}

		if (this.paramsJS.layOut.ols){
			this.addEvents('onOlsMethod');
			this.addEvents('onOlsReverseGeocoding');
			this.addEvents('onOlsStartPoint');
			this.addEvents('onOlsViaPoint');
			this.addEvents('onOlsEndPoint');
			this.addEvents('onOlsReset');
			
			var onOlsMethod = function(item, checked) {
				if (item.method != this.olsMethod) {
					this.olsMethod = item.method;
					this.fireEvent('onOlsMethod', this.olsMethod);
				}
			}
			
			this.add("-");
			
			var olsMethodItems = [
				{
                    text: ToloI18n.getMsg("ToloContextMenu.OLS.piuveloce"),
                    method: 'Fastest',
                    group: 'olsMethods',                        
                    xtype: 'menucheckitem',
                    listeners: {click: {fn: onOlsMethod,  scope: this}},
                    checked: true
                },{
                    text: ToloI18n.getMsg("ToloContextMenu.OLS.piucorto"),
                    method: 'Shortest',
                    group: 'olsMethods',                        
                    xtype: 'menucheckitem',
                    listeners: {click: {fn: onOlsMethod,  scope: this}}
                },{
                    text: ToloI18n.getMsg("ToloContextMenu.OLS.apiedi"),
                    method: 'Pedestrian',
                    group: 'olsMethods',                        
                    xtype: 'menucheckitem',
                    listeners: {click: {fn: onOlsMethod,  scope: this}}
                }
            ];
			
			var olsItems = [
				{
                    text: ToloI18n.getMsg("ToloContextMenu.OLS.indirizzo"),
                    listeners: {click: {fn: function() {
            			this.fireEvent('onOlsReverseGeocoding', this.getXEvtPos(), this.getYEvtPos());
        			},  scope: this}}
                },{
                    text: '-',
                    xtype: 'menuseparator'
                },{
                    text: ToloI18n.getMsg("ToloContextMenu.OLS.partenza"),
    				icon: this.iconBasePath + 'ols/start.png',
                    listeners: {click: {fn: function() {
            			this.fireEvent('onOlsStartPoint', this.getXEvtPos(), this.getYEvtPos());
        			},  scope: this}}
                },{
                    text: ToloI18n.getMsg("ToloContextMenu.OLS.destIntermedia"),
    				icon: this.iconBasePath + 'ols/via.png',
                    listeners: {click: {fn: function() {
            			this.fireEvent('onOlsViaPoint', this.getXEvtPos(), this.getYEvtPos());
        			},  scope: this}}
                },{
                    text: ToloI18n.getMsg("ToloContextMenu.OLS.arrivo"),
    				icon: this.iconBasePath + 'ols/stop.png',
                    listeners: {click: {fn: function() {
            			this.fireEvent('onOlsEndPoint', this.getXEvtPos(), this.getYEvtPos());
        			},  scope: this}}
                },{
                    text: '-',
                    xtype: 'menuseparator'
                },{
    				text: ToloI18n.getMsg("ToloContextMenu.OLS.modalita"),
    				menu: {
    					cls: 'clearCSS',
    	                items: olsMethodItems
    	            }
    			},{
                    text: '-',
                    xtype: 'menuseparator'
                },{
                    text: ToloI18n.getMsg("ToloContextMenu.OLS.cancellapercorso"),
                    icon: this.iconBasePath + 'ols/erase.png',
                    listeners: {click: {fn: function() {
            			this.fireEvent('onOlsReset', this.getXEvtPos(), this.getYEvtPos());
        			},  scope: this}}
                }
            ];
			
			this.add({
				text: ToloI18n.getMsg("ToloContextMenu.OLS.navigazione"),
				menu: {
					cls: 'clearCSS',
	                items: olsItems
	            },
				handlerBaseName : 'ReleaseOls'
			});
		}
		
		if (this.paramsJS.layOut.conStreetView){
			this.add("-");
			this.add({
				text: ToloI18n.getMsg("ToloContextMenu.Streetview"),
				icon: this.iconBasePath + 'streetview16.png',
				//icon: this.iconBasePath + 'eye-arrow.png',
				handlerBaseName : 'ReleaseStreetview',
				listeners: {click: {fn: notifyReleaseStreetview,  scope: thisContextMenu}}
			});
		}
		
		
		this.doLayout();
	
	},

	/**
	 * @method menuItemHandler
	 * 
	 * 
	 * @param {Object} button
	 * il pulsante.
	 * 
	 * @param {Object} e
	 * l'evento.
	 * 
	 * @return {Boolean}
	 * 
	 * 
	 */
	btnClickHandler: function (button, e) {
		if (button.handlerBaseName !=null) {
			var eventName = 'on' + button.handlerBaseName + 'ClickFn';
			this.fireEvent(eventName, button);
		}		
		return true;
	},

	/**
	 * @method bindToAPI
	 * 
	 * 
	 * @param {Object} api
	 * API.
	 * 
	 */
	bindToAPI: function(api) {
		this.api=api;
		// Eventi API ai quali viene registrato buttonsPanel
		/*
		api.on('onOperationEnable', function (opCode) {this.operationEnable(opCode, true);}, this );
		api.on('onOperationDisable', function (opCode) {this.operationEnable(opCode, false);}, this );
		api.on('onOperationPressDefault', function (group) {this.pressDefault(group);}, this );
		*/
	},
	
	/**
	 * @method showAt
	 * Metodo sovrascritto per registrarsi la posizione x ed y
	 * 
	 * @param {Array} xyPosition
	 * 
	 * 
	 * @param {Object} parentMenu
	 * 
	 * 
	 */ 
	showAt: function(xyPosition,parentMenu) {
		this.xEvtPos = xyPosition[0];
		this.yEvtPos = xyPosition[1];
		//TolomeoExt.ToloContextMenu.superclass.showAt.apply(this, arguments);
		this.callParent(arguments);
	},
	
	/**
	 * @method getXEvtPos
	 * 
	 * 
	 * @return {Number}
	 * posizione x dell'evento originante
	 * 
	 */
	getXEvtPos: function(){
		return this.xEvtPos;
	},
	
	/**
	 * @method getYEvtPos
	 * 
	 * 
	 * @return {Number}
	 * posizione y dell'evento originante
	 * 
	 */
	getYEvtPos: function(){
		return this.yEvtPos;
	},
	
	/**
	 * @method setCrsSelected
	 * Imposta il Sistema di coordinate da mostrare
	 * 
	 * @param {String} projCode
	 * 
	 * 
	 */
	setCrsSelected: function(projCode){
		var relLoc = this.getComponent(this.getId() + 'releaseLoc');
		if(relLoc){
			var prjItem = relLoc.menu.items.get('chk_'+projCode);
			if(prjItem){
				prjItem.setChecked(true,true);
			}
		}
		this.crsSelected = projCode;
	}
			
});
/**
 * Basic status bar component that can be used as the bottom toolbar of any {@link Ext.Panel}.  In addition to
 * supporting the standard {@link Ext.toolbar.Toolbar} interface for adding buttons, menus and other items, the StatusBar
 * provides a greedy status element that can be aligned to either side and has convenient methods for setting the
 * status text and icon.  You can also indicate that something is processing using the {@link #showBusy} method.
 *
 *     Ext.create('Ext.Panel', {
 *         title: 'StatusBar',
 *         // etc.
 *         bbar: Ext.create('Ext.ux.StatusBar', {
 *             id: 'my-status',
 *      
 *             // defaults to use when the status is cleared:
 *             defaultText: 'Default status text',
 *             defaultIconCls: 'default-icon',
 *      
 *             // values to set initially:
 *             text: 'Ready',
 *             iconCls: 'ready-icon',
 *      
 *             // any standard Toolbar items:
 *             items: [{
 *                 text: 'A Button'
 *             }, '-', 'Plain Text']
 *         })
 *     });
 *
 *     // Update the status bar later in code:
 *     var sb = Ext.getCmp('my-status');
 *     sb.setStatus({
 *         text: 'OK',
 *         iconCls: 'ok-icon',
 *         clear: true // auto-clear after a set interval
 *     });
 *
 *     // Set the status bar to show that something is processing:
 *     sb.showBusy();
 *
 *     // processing....
 *
 *     sb.clearStatus(); // once completeed
 *
 */
Ext.define('Ext.ux.statusbar.StatusBar', {
    extend: 'Ext.toolbar.Toolbar',
    alternateClassName: 'Ext.ux.StatusBar',
    alias: 'widget.statusbar',
    requires: ['Ext.toolbar.TextItem'],
    /**
     * @cfg {String} statusAlign
     * The alignment of the status element within the overall StatusBar layout.  When the StatusBar is rendered,
     * it creates an internal div containing the status text and icon.  Any additional Toolbar items added in the
     * StatusBar's {@link #cfg-items} config, or added via {@link #method-add} or any of the supported add* methods, will be
     * rendered, in added order, to the opposite side.  The status element is greedy, so it will automatically
     * expand to take up all sapce left over by any other items.  Example usage:
     *
     *     // Create a left-aligned status bar containing a button,
     *     // separator and text item that will be right-aligned (default):
     *     Ext.create('Ext.Panel', {
     *         title: 'StatusBar',
     *         // etc.
     *         bbar: Ext.create('Ext.ux.statusbar.StatusBar', {
     *             defaultText: 'Default status text',
     *             id: 'status-id',
     *             items: [{
     *                 text: 'A Button'
     *             }, '-', 'Plain Text']
     *         })
     *     });
     *
     *     // By adding the statusAlign config, this will create the
     *     // exact same toolbar, except the status and toolbar item
     *     // layout will be reversed from the previous example:
     *     Ext.create('Ext.Panel', {
     *         title: 'StatusBar',
     *         // etc.
     *         bbar: Ext.create('Ext.ux.statusbar.StatusBar', {
     *             defaultText: 'Default status text',
     *             id: 'status-id',
     *             statusAlign: 'right',
     *             items: [{
     *                 text: 'A Button'
     *             }, '-', 'Plain Text']
     *         })
     *     });
     */
    /**
     * @cfg {String} [defaultText='']
     * The default {@link #text} value.  This will be used anytime the status bar is cleared with the
     * `useDefaults:true` option.
     */
    /**
     * @cfg {String} [defaultIconCls='']
     * The default {@link #iconCls} value (see the iconCls docs for additional details about customizing the icon).
     * This will be used anytime the status bar is cleared with the `useDefaults:true` option.
     */
    /**
     * @cfg {String} text
     * A string that will be <b>initially</b> set as the status message.  This string
     * will be set as innerHTML (html tags are accepted) for the toolbar item.
     * If not specified, the value set for {@link #defaultText} will be used.
     */
    /**
     * @cfg {String} [iconCls='']
     * A CSS class that will be **initially** set as the status bar icon and is
     * expected to provide a background image.
     *
     * Example usage:
     *
     *     // Example CSS rule:
     *     .x-statusbar .x-status-custom {
     *         padding-left: 25px;
     *         background: transparent url(images/custom-icon.gif) no-repeat 3px 2px;
     *     }
     *
     *     // Setting a default icon:
     *     var sb = Ext.create('Ext.ux.statusbar.StatusBar', {
     *         defaultIconCls: 'x-status-custom'
     *     });
     *
     *     // Changing the icon:
     *     sb.setStatus({
     *         text: 'New status',
     *         iconCls: 'x-status-custom'
     *     });
     */

    /**
     * @cfg {String} cls
     * The base class applied to the containing element for this component on render.
     */
    cls : 'x-statusbar',
    /**
     * @cfg {String} busyIconCls
     * The default {@link #iconCls} applied when calling {@link #showBusy}.
     * It can be overridden at any time by passing the `iconCls` argument into {@link #showBusy}.
     */
    busyIconCls : 'x-status-busy',
    /**
     * @cfg {String} busyText
     * The default {@link #text} applied when calling {@link #showBusy}.
     * It can be overridden at any time by passing the `text` argument into {@link #showBusy}.
     */
    busyText : 'Loading...',
    /**
     * @cfg {Number} autoClear
     * The number of milliseconds to wait after setting the status via
     * {@link #setStatus} before automatically clearing the status text and icon.
     * Note that this only applies when passing the `clear` argument to {@link #setStatus}
     * since that is the only way to defer clearing the status.  This can
     * be overridden by specifying a different `wait` value in {@link #setStatus}.
     * Calls to {@link #clearStatus} always clear the status bar immediately and ignore this value.
     */
    autoClear : 5000,

    /**
     * @cfg {String} emptyText
     * The text string to use if no text has been set. If there are no other items in
     * the toolbar using an empty string (`''`) for this value would end up in the toolbar
     * height collapsing since the empty string will not maintain the toolbar height.
     * Use `''` if the toolbar should collapse in height vertically when no text is
     * specified and there are no other items in the toolbar.
     */
    emptyText : '&#160;',

    // private
    activeThreadId : 0,

    // private
    initComponent : function(){
        var right = this.statusAlign === 'right';

        this.callParent(arguments);
        this.currIconCls = this.iconCls || this.defaultIconCls;
        this.statusEl = Ext.create('Ext.toolbar.TextItem', {
            cls: 'x-status-text ' + (this.currIconCls || ''),
            text: this.text || this.defaultText || ''
        });

        if (right) {
            this.cls += ' x-status-right';
            this.add('->');
            this.add(this.statusEl);
        } else {
            this.insert(0, this.statusEl);
            this.insert(1, '->');
        }
    },

    /**
     * Sets the status {@link #text} and/or {@link #iconCls}. Also supports automatically clearing the
     * status that was set after a specified interval.
     *
     * Example usage:
     *
     *     // Simple call to update the text
     *     statusBar.setStatus('New status');
     *
     *     // Set the status and icon, auto-clearing with default options:
     *     statusBar.setStatus({
     *         text: 'New status',
     *         iconCls: 'x-status-custom',
     *         clear: true
     *     });
     *
     *     // Auto-clear with custom options:
     *     statusBar.setStatus({
     *         text: 'New status',
     *         iconCls: 'x-status-custom',
     *         clear: {
     *             wait: 8000,
     *             anim: false,
     *             useDefaults: false
     *         }
     *     });
     *
     * @param {Object/String} config A config object specifying what status to set, or a string assumed
     * to be the status text (and all other options are defaulted as explained below). A config
     * object containing any or all of the following properties can be passed:
     *
     * @param {String} config.text The status text to display.  If not specified, any current
     * status text will remain unchanged.
     *
     * @param {String} config.iconCls The CSS class used to customize the status icon (see
     * {@link #iconCls} for details). If not specified, any current iconCls will remain unchanged.
     *
     * @param {Boolean/Number/Object} config.clear Allows you to set an internal callback that will
     * automatically clear the status text and iconCls after a specified amount of time has passed. If clear is not
     * specified, the new status will not be auto-cleared and will stay until updated again or cleared using
     * {@link #clearStatus}. If `true` is passed, the status will be cleared using {@link #autoClear},
     * {@link #defaultText} and {@link #defaultIconCls} via a fade out animation. If a numeric value is passed,
     * it will be used as the callback interval (in milliseconds), overriding the {@link #autoClear} value.
     * All other options will be defaulted as with the boolean option.  To customize any other options,
     * you can pass an object in the format:
     * 
     * @param {Number} config.clear.wait The number of milliseconds to wait before clearing
     * (defaults to {@link #autoClear}).
     * @param {Boolean} config.clear.anim False to clear the status immediately once the callback
     * executes (defaults to true which fades the status out).
     * @param {Boolean} config.clear.useDefaults False to completely clear the status text and iconCls
     * (defaults to true which uses {@link #defaultText} and {@link #defaultIconCls}).
     *
     * @return {Ext.ux.statusbar.StatusBar} this
     */
    setStatus : function(o) {
        var me = this;

        o = o || {};
        Ext.suspendLayouts();
        if (Ext.isString(o)) {
            o = {text:o};
        }
        if (o.text !== undefined) {
            me.setText(o.text);
        }
        if (o.iconCls !== undefined) {
            me.setIcon(o.iconCls);
        }

        if (o.clear) {
            var c = o.clear,
                wait = me.autoClear,
                defaults = {useDefaults: true, anim: true};

            if (Ext.isObject(c)) {
                c = Ext.applyIf(c, defaults);
                if (c.wait) {
                    wait = c.wait;
                }
            } else if (Ext.isNumber(c)) {
                wait = c;
                c = defaults;
            } else if (Ext.isBoolean(c)) {
                c = defaults;
            }

            c.threadId = this.activeThreadId;
            Ext.defer(me.clearStatus, wait, me, [c]);
        }
        Ext.resumeLayouts(true);
        return me;
    },

    /**
     * Clears the status {@link #text} and {@link #iconCls}. Also supports clearing via an optional fade out animation.
     *
     * @param {Object} [config] A config object containing any or all of the following properties.  If this
     * object is not specified the status will be cleared using the defaults below:
     * @param {Boolean} config.anim True to clear the status by fading out the status element (defaults
     * to false which clears immediately).
     * @param {Boolean} config.useDefaults True to reset the text and icon using {@link #defaultText} and
     * {@link #defaultIconCls} (defaults to false which sets the text to '' and removes any existing icon class).
     *
     * @return {Ext.ux.statusbar.StatusBar} this
     */
    clearStatus : function(o) {
        o = o || {};

        var me = this,
            statusEl = me.statusEl;

        if (o.threadId && o.threadId !== me.activeThreadId) {
            // this means the current call was made internally, but a newer
            // thread has set a message since this call was deferred.  Since
            // we don't want to overwrite a newer message just ignore.
            return me;
        }

        var text = o.useDefaults ? me.defaultText : me.emptyText,
            iconCls = o.useDefaults ? (me.defaultIconCls ? me.defaultIconCls : '') : '';

        if (o.anim) {
            // animate the statusEl Ext.Element
            statusEl.el.puff({
                remove: false,
                useDisplay: true,
                callback: function() {
                    statusEl.el.show();
                    me.setStatus({
                        text: text,
                        iconCls: iconCls
                    });
                }
            });
        } else {
             me.setStatus({
                 text: text,
                 iconCls: iconCls
             });
        }
        return me;
    },

    /**
     * Convenience method for setting the status text directly.  For more flexible options see {@link #setStatus}.
     * @param {String} text (optional) The text to set (defaults to '')
     * @return {Ext.ux.statusbar.StatusBar} this
     */
    setText : function(text) {
        var me = this;
        me.activeThreadId++;
        me.text = text || '';
        if (me.rendered) {
            me.statusEl.setText(me.text);
        }
        return me;
    },

    /**
     * Returns the current status text.
     * @return {String} The status text
     */
    getText : function(){
        return this.text;
    },

    /**
     * Convenience method for setting the status icon directly.  For more flexible options see {@link #setStatus}.
     * See {@link #iconCls} for complete details about customizing the icon.
     * @param {String} iconCls (optional) The icon class to set (defaults to '', and any current icon class is removed)
     * @return {Ext.ux.statusbar.StatusBar} this
     */
    setIcon : function(cls) {
        var me = this;

        me.activeThreadId++;
        cls = cls || '';

        if (me.rendered) {
            if (me.currIconCls) {
                me.statusEl.removeCls(me.currIconCls);
                me.currIconCls = null;
            }
            if (cls.length > 0) {
                me.statusEl.addCls(cls);
                me.currIconCls = cls;
            }
        } else {
            me.currIconCls = cls;
        }
        return me;
    },

    /**
     * Convenience method for setting the status text and icon to special values that are pre-configured to indicate
     * a "busy" state, usually for loading or processing activities.
     *
     * @param {Object/String} config (optional) A config object in the same format supported by {@link #setStatus}, or a
     * string to use as the status text (in which case all other options for setStatus will be defaulted).  Use the
     * `text` and/or `iconCls` properties on the config to override the default {@link #busyText}
     * and {@link #busyIconCls} settings. If the config argument is not specified, {@link #busyText} and
     * {@link #busyIconCls} will be used in conjunction with all of the default options for {@link #setStatus}.
     * @return {Ext.ux.statusbar.StatusBar} this
     */
    showBusy : function(o){
        if (Ext.isString(o)) {
            o = { text: o };
        }
        o = Ext.applyIf(o || {}, {
            text: this.busyText,
            iconCls: this.busyIconCls
        });
        return this.setStatus(o);
    }
});
/*!
 * Ext Core Library $version&#xD;&#xA;http://extjs.com/&#xD;&#xA;Copyright(c) 2006-2009, $author.&#xD;&#xA;&#xD;&#xA;The MIT License&#xD;&#xA;&#xD;&#xA;Permission is hereby granted, free of charge, to any person obtaining a copy&#xD;&#xA;of this software and associated documentation files (the &quot;Software&quot;), to deal&#xD;&#xA;in the Software without restriction, including without limitation the rights&#xD;&#xA;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&#xD;&#xA;copies of the Software, and to permit persons to whom the Software is&#xD;&#xA;furnished to do so, subject to the following conditions:&#xD;&#xA;&#xD;&#xA;The above copyright notice and this permission notice shall be included in&#xD;&#xA;all copies or substantial portions of the Software.&#xD;&#xA;&#xD;&#xA;THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&#xD;&#xA;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&#xD;&#xA;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&#xD;&#xA;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&#xD;&#xA;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&#xD;&#xA;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&#xD;&#xA;THE SOFTWARE.&#xD;&#xA;
 */
Ext.define('Ext.ux.Carousel', {
		extend: 'Ext.util.Observable',

    interval: 3,
    transitionDuration: 1,
    transitionType: 'carousel',
    transitionEasing: 'easeOut',
    itemSelector: 'img',
    activeSlide: 0,
    autoPlay: false,
    showPlayButton: false,
    pauseOnNavigate: false,
    wrap: false,
    freezeOnHover: false,
    navigationOnHover: false,
    hideNavigation: false,
    width: null,
    height: null,

    constructor: function(elId, config) {
        config = config || {};
        Ext.apply(this, config);

        this.callParent(arguments);
        
        this.addEvents(
            'beforeprev',
            'prev',
            'beforenext',
            'next',
            'change',
            'play',
            'pause',
            'freeze',
            'unfreeze'
        );

        this.el = Ext.get(elId);
        this.slides = this.els = [];
        
        if(this.autoPlay || this.showPlayButton) {
            this.wrap = true;
        };

        if(this.autoPlay && typeof config.showPlayButton === 'undefined') {
            this.showPlayButton = true;
        }

        this.initMarkup();
        this.initEvents();

        if(this.carouselSize > 0) {
            this.refresh();
        }
    },

    initMarkup: function() {
        var dh = Ext.DomHelper;
        
        this.carouselSize = 0;
        var items = this.el.select(this.itemSelector);
        this.els.container = dh.append(this.el, {cls: 'ux-carousel-container'}, true);
        this.els.slidesWrap = dh.append(this.els.container, {cls: 'ux-carousel-slides-wrap'}, true);

        this.els.navigation = dh.append(this.els.container, {cls: 'ux-carousel-nav'}, true).hide();
        this.els.caption = dh.append(this.els.navigation, {tag: 'h2', cls: 'ux-carousel-caption'}, true);
        this.els.navNext = dh.append(this.els.navigation, {tag: 'a', href: '#', cls: 'ux-carousel-nav-next'}, true);
        if(this.showPlayButton) {
            this.els.navPlay = dh.append(this.els.navigation, {tag: 'a', href: '#', cls: 'ux-carousel-nav-play'}, true)
        }
        this.els.navPrev = dh.append(this.els.navigation, {tag: 'a', href: '#', cls: 'ux-carousel-nav-prev'}, true);

        // set the dimensions of the container
        this.slideWidth = this.width || this.el.getWidth(true);
        this.slideHeight = this.height || this.el.getHeight(true);
        this.els.container.setStyle({
            width: this.slideWidth + 'px',
            height: this.slideHeight + 'px'
        });        
        
        var w = Math.max((this.slideWidth - (this.els.navNext.getWidth()*2) - (this.showPlayButton ? this.els.navPlay.getWidth() : 0) - 20),0);        
        this.els.caption.setWidth(w  + 'px');
        
        items.appendTo(this.els.slidesWrap).each(function(item) {
            item = item.wrap({cls: 'ux-carousel-slide'});
            this.slides.push(item);
            item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
        }, this);
        this.carouselSize = this.slides.length;
        if(this.navigationOnHover) {
            this.els.navigation.setStyle('top', (-1*this.els.navigation.getHeight()) + 'px');
        }
        this.el.clip();
    },

    resize: function() {

    	   	
    	var items = this.el.select(this.itemSelector);
    	
        // set the dimensions of the container
        this.slideWidth = this.el.getWidth(true);
        this.slideHeight = this.el.getHeight(true);
        
        var offset = this.activeSlide * this.slideWidth;
    	this.els.slidesWrap.setStyle('left', (-1 * offset) + 'px');
    	this.els.slidesWrap.setWidth((this.slideWidth * this.carouselSize) + 'px');
    	
        this.els.container.setStyle({
            width: this.slideWidth + 'px',
            height: this.slideHeight + 'px'
        });

        this.els.caption.setWidth((this.slideWidth - (this.els.navNext.getWidth()*2) - (this.showPlayButton ? this.els.navPlay.getWidth() : 0) - 20) + 'px')
        
        items.each(function(item) {
        	var item = item.parent();
            item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
        	//ale
            item = item.parent();
            item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
        }, this);
        if(this.navigationOnHover) {
            this.els.navigation.setStyle('top', (-1*this.els.navigation.getHeight()) + 'px');
        }
        
        
        //this.el.clip();
    },
    
    setOffset: function(x,y) {
    	
        var items = this.el.select(this.itemSelector);
        
    	items.each(function(item) {
        	var item = item.parent();
            item.setStyle('top',  y + 'px')
            item.setStyle('left',  x + 'px')
        }, this);
    	
    },
    
    initEvents: function() {
        this.els.navPrev.on('click', function(ev) {
            ev.preventDefault();
            var target = ev.getTarget();
            target.blur();            
            if(Ext.fly(target).hasCls('ux-carousel-nav-disabled')) return;
            this.prev();
        }, this);

        this.els.navNext.on('click', function(ev) {
            ev.preventDefault();
            var target = ev.getTarget();
            target.blur();
            if(Ext.fly(target).hasCls('ux-carousel-nav-disabled')) return;
            this.next();
        }, this);

        if(this.showPlayButton) {
            this.els.navPlay.on('click', function(ev){
                ev.preventDefault();
                ev.getTarget().blur();
                if(this.playing) {
                    this.pause();
                }
                else {
                    this.play();
                }
            }, this);
        };

        if(this.freezeOnHover) {
            this.els.container.on('mouseenter', function(){
                if(this.playing) {
                    this.fireEvent('freeze', this.slides[this.activeSlide]);
                    Ext.TaskManager.stop(this.playTask);
                }
            }, this);
            this.els.container.on('mouseleave', function(){
                if(this.playing) {
                    this.fireEvent('unfreeze', this.slides[this.activeSlide]);
                    Ext.TaskManager.start(this.playTask);
                }
            }, this, {buffer: (this.interval/2)*1000});
        };

        if(this.navigationOnHover) {
            this.els.container.on('mouseenter', function(){
                if(!this.navigationShown) {
                    this.navigationShown = true;
                    this.els.navigation.stopFx(false).shift({
                        y: this.els.container.getY(),
                        duration: this.transitionDuration
                    })
                }
            }, this);

            this.els.container.on('mouseleave', function(){
                if(this.navigationShown) {
                    this.navigationShown = false;
                    this.els.navigation.stopFx(false).shift({
                        y: this.els.navigation.getHeight() - this.els.container.getY(),
                        duration: this.transitionDuration
                    })
                }
            }, this);
        }

        if(this.interval && this.autoPlay) {
            this.play();
        };
    },

    prev: function() {
        if (this.fireEvent('beforeprev') === false) {
            return;
        }
        if(this.pauseOnNavigate) {
            this.pause();
        }
        this.setSlide(this.activeSlide - 1);

        this.fireEvent('prev', this.activeSlide);        
        return this; 
    },
    
    next: function() {
        if(this.fireEvent('beforenext') === false) {
            return;
        }
        if(this.pauseOnNavigate) {
            this.pause();
        }
        this.setSlide(this.activeSlide + 1);

        this.fireEvent('next', this.activeSlide);        
        return this;         
    },

    play: function() {
        if(!this.playing) {
            this.playTask = this.playTask || {
                run: function() {
                    this.playing = true;
                    this.setSlide(this.activeSlide+1);
                },
                interval: this.interval*1000,
                scope: this
            };
            
            this.playTaskBuffer = this.playTaskBuffer || new Ext.util.DelayedTask(function() {
                Ext.TaskManager.start(this.playTask);
            }, this);

            this.playTaskBuffer.delay(this.interval*1000);
            this.playing = true;
            if(this.showPlayButton) {
                this.els.navPlay.addCls('ux-carousel-playing');
            }
            this.fireEvent('play');
        }        
        return this;
    },

    pause: function() {
        if(this.playing) {
            Ext.TaskManager.stop(this.playTask);
            this.playTaskBuffer.cancel();
            this.playing = false;
            if(this.showPlayButton) {
                this.els.navPlay.removeCls('ux-carousel-playing');
            }
            this.fireEvent('pause');
        }        
        return this;
    },
        
    clear: function() {
        this.els.slidesWrap.update('');
        this.slides = [];
        this.carouselSize = 0;
        this.pause();
        return this;
    },
    
    add: function(el, refresh) {
    	
        /* Originale
        var item = Ext.fly(el).appendTo(this.els.slidesWrap).wrap({cls: 'ux-carousel-slide'});
        item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
        */
    	//ale
        //  item = item.wrap({style: 'position: relative; left:0px; top: 0px; '});
    	
    	var item = Ext.fly(el).appendTo(this.els.slidesWrap).wrap({style: 'position: relative; left:0px; top: 0px; '});
    	item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
    	
    	item =item.wrap({cls: 'ux-carousel-slide'});
        item.setWidth(this.slideWidth + 'px').setHeight(this.slideHeight + 'px');
    	
    	
        this.slides.push(item);                        
        if(refresh) {
            this.refresh();
        }        
        return this;
    },
    
    refresh: function(slide) {
        this.carouselSize = this.slides.length;
        this.els.slidesWrap.setWidth((this.slideWidth * this.carouselSize) + 'px');
        if(this.carouselSize > 0) {
            if(!this.hideNavigation) this.els.navigation.show();
            this.setSlide((slide) ? slide : 0, slide==null || slide==0);
        }                
        return this;        
    },
    
    setSlide: function(index, initial) {
        if(!this.wrap && !this.slides[index]) {
            return;
        }
        else if(this.wrap) {
            if(index < 0) {
                index = this.carouselSize-1;
            }
            else if(index > this.carouselSize-1) {
                index = 0;
            }
        }
        if(!this.slides[index]) {
            return;
        }

        // controllo se immagine è caricata ed eventualmente la carico
        var a = this.slides[index].dom.childNodes[0].childNodes[0];
        if (a.isLoaded && a.isLoaded()==false) {
        	a.load();
        }
        
        this.els.caption.update(this.slides[index].child(':first-child', false).child(':first-child', true).title || '');
        var offset = index * this.slideWidth;
        if (!initial) {
            switch (this.transitionType) {
                case 'fade':
                    this.slides[index].setOpacity(0);
                    //this.slides[this.activeSlide].stopFx(false).fadeOut({
                    this.slides[this.activeSlide].stopAnimation().fadeOut({
                        duration: this.transitionDuration / 2,
                        callback: function(){
                            this.els.slidesWrap.setStyle('left', (-1 * offset) + 'px');
                            this.slides[this.activeSlide].setOpacity(1);
                            this.slides[index].fadeIn({
                                duration: this.transitionDuration / 2
                            });
                        },
                        scope: this
                    })
                    break;

                default:
                    var xNew = (-1 * offset) + this.els.container.getX();
                    this.els.slidesWrap.stopAnimation();
                    this.els.slidesWrap.shift({
                        duration: this.transitionDuration,
                        x: xNew,
                        easing: this.transitionEasing
                    });
                    break;
            }
        }
        else {
            this.els.slidesWrap.setStyle('left', '0');
        }

        this.activeSlide = index;
        this.updateNav();
        this.fireEvent('change', this.slides[index], index);
    },

    updateNav: function() {
        this.els.navPrev.removeCls('ux-carousel-nav-disabled');
        this.els.navNext.removeCls('ux-carousel-nav-disabled');
        if(!this.wrap) {
            if(this.activeSlide === 0) {
                this.els.navPrev.addCls('ux-carousel-nav-disabled');
            }
            if(this.activeSlide === this.carouselSize-1) {
                this.els.navNext.addCls('ux-carousel-nav-disabled');
            }
        }
    }
});
/**
 * @class Ext.ux.CarouselPanel
 * @author Alessandro Radaelli - Comune di Prato
 * 
 */
Ext.define('Ext.ux.CarouselPanel', {
	extend: 'Ext.Panel',

	carousel: null,
	carouselItems: null,
	carouselConfig: null,
	carouselFixedLeft: null,
	carouselFixedTop: null,
	autoOffsetXAdjust:0,
	autoOffsetYAdjust:0,
	draggableObj: null,
	
	autoDraggableDetect: true,
	
	// private
	itemsToAppend: null,
	
	initComponent: function(){
		
		this.layout= 'fit';
		this.autoScroll= true;
	    this.itemsToAppend = (this.carouselItems!=null) ? this.carouselItems : [];
	    if (this.carouselFixedLeft!=null && this.carouselFixedTop!=null && this.autoDraggableDetect) this.on('added', this.addedHandler, this);
	    
	    this.addEvents('draggableObjInitialized');
	    
	    if (this.draggable && this.autoDraggableDetect) {
	    	this.draggableObj = this;
	    	this.fireEvent(draggableObjInitialized, this.draggableObj);
	    } 
	    
	    this.callParent(arguments);
	
	},
	
	addedHandler: function(thisComponent, ownerCt, index) {
		
		if (ownerCt && ownerCt.draggable) {
	    	this.setDraggableObj(ownerCt);
	    }
		
	},
	/*
	_setDDOwner: function() {

			var thisPanel=this;
    		//if (!this.draggableObj.dd) {
    			//Ext.dd.DD
    			this.draggableObj.dd = new Ext.dd.DD(this.draggableObj.getId()); //this.draggableObj
    			//this.draggableObj.dd.setDragElId(this.body.id);
    			this.draggableObj.dd.constrainTo(Ext.get(this.getEl())); //this.draggableObj.renderTo
        		this.draggableObj.dd.startDrag = this.draggableObj.dd.startDrag.createSequence(
    		    										function(){
    										    	        var w = thisPanel.draggableObj;
    										    	        var so = w.el.shadowOffset;
    										    	        this.constrainTo(w.container, {right: so, left: so, bottom: so});
    										    	    });
    		//}
    		this.draggableObj.dd.onDrag = this.draggableObj.dd.onDrag.createSequence(thisPanel.onDragHandler, thisPanel);
    		
    		this.fireEvent('draggableObjInitialized', this.draggableObj);
	}, 
	*/
	setDraggableObj: function(draggableObj) {

		if ( draggableObj.draggable) {
			this.draggableObj = draggableObj;
			if (this.draggableObj) {
				//var thisPanel=this;
		    	/*if (this.draggableObj.rendered) {
		    		if (this.rendered) {
		    			this._setDDOwner();	
		    		}
		    		else 
		    			this.on('afterrender', this._setDDOwner, thisPanel, {single:true});
		    	} else {
		    		this.draggableObj.on('afterrender', this._setDDOwner, thisPanel, {single:true});
		    	}*/
		    	
		    	this.draggableObj.on('move', this.onDragHandler, this);	    		
		    	this.draggableObj.on('expand', this.onDragHandler, this);
		
		    }
		} 
	},
	
	
	removed : function( thisComponent, ownerCt ) {
		//????
		
	}, 
	
    /**
     * Method: afterRender
     * Metodo privato invocato dopo che il pannello è stato renderizzato.
     * 
     */
    afterRender: function() {    	
    	this.callParent(arguments);
    	
		this.carousel = Ext.create('Ext.ux.Carousel', this.body.id, this.carouselConfig);
		this.on('resize', this.carousel.resize, this.carousel);
		this.on('maximize', this.carousel.resize, this.carousel);
		if (this.itemsToAppend!=null) {
			for (var i=0; i<this.itemsToAppend.length; i++) {
				this.carousel.add(this.itemsToAppend[i], false);
			}
			this.autoOffset();
			this.carousel.refresh();
		}
			
    },
	
	prevItem: function() {
		if (this.carousel) this.carousel.prev();
        return this.carousel; 
    },
    
    nextItem: function() {
    	if (this.carousel) this.carousel.next();
        return this.carousel;         
    },

    play: function() {
    	if (this.carousel) this.carousel.play();
        return this.carousel;
    },

    pause: function() {
    	if (this.carousel) this.carousel.pause();        
        return this.carousel;
    },
        
    clearItems: function() {
    	if (this.carousel) this.carousel.clear();
        return this.carousel;
    },
    
    addImgItem: function(imgid, imgurl, imgtitle, refresh) {
    	
    	var docbody = Ext.getBody();
      	var imgel = Ext.DomHelper.insertHtml('afterBegin', docbody.dom, '<img id="'+ imgid +'" title="'+ imgtitle +'" />');
    	
      	imgel.srctoload=imgurl;
      	imgel.isLoaded=function() {return this.src && this.src!=""; };
      	imgel.load=function() { this.src=this.srctoload; };
      	
      	
      	this.addItem(imgid, refresh);
    },
    
    addItem: function(el, refresh) {
    	
    	if (this.carousel) {
    		this.carousel.add(el, refresh);
    		this.autoOffset();
    	} else {
    		this.itemsToAppend.push(el);
    	}
        return this.carousel;
    },
    
    refresh: function(slide) {
    	if (this.carousel) this.carousel.refresh(slide);                
        return this.carousel;        
    },
    
    setSlide: function(index, initial) {
    	if (this.carousel) this.carousel.setSlide(index, initial);
    },
    
    setOffset: function(xOffset, yOffset) {
    	if (this.carousel) this.carousel.setOffset(xOffset, yOffset);
    },
    
    autoOffset: function() {
    	var pos = this.getPosition(false);
    	var xOffset = this.carouselFixedLeft - pos[0] + this.autoOffsetXAdjust;
    	var yOffset = this.carouselFixedTop - pos[1] + this.autoOffsetYAdjust;
    	
    	if (this.carousel) this.setOffset(xOffset, yOffset);
    	
    },

	setCarouselFixed: function(newCarouselFixedLeft, newCarouselFixedTop) {
		this.carouselFixedLeft = newCarouselFixedLeft;
		this.carouselFixedTop  = newCarouselFixedTop;
		this.autoOffset();
	},
    
    onDragHandler: function() {

    	this.autoOffset();
		return 	true;
    
    }
    
	
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloTimeMachinePanel
 * @extends Ext.Panel
 * Pannello ExtJs che implementa la funzionalità TimeMachine
 * 
 * @param {Object} config
 * 
 * 
 * @param {Object} config.paramsJS
 * Oggetto i parametri contenuti nel file di preset.  
 * 
 * @author Ing. Alessandro Radaelli
 */
Ext.define('TolomeoExt.ToloTimeMachinePanel', {
	
		extend: 'Ext.ux.CarouselPanel',
		
		/** 
		 * @property {Object} paramsJS
		 * 
		 * 
		 */
		paramsJS : null,
		
		
		/** 
		 * @property {TolomeoExt.ToloViewerOLPanel} viewer 
		 * 
		 * 
		 */
		viewer: null,
		
		/**
		 * @property {Object} timeMachineToShow
		 * In caso di multiTimeMachine (this.paramsJS.mappe.mappaList[0].timeMachineList.length>1) indica quale deve essere visualizzata da questo pannello. Se non valorizzato per retrocampatibilità mostra this.paramsJS.mappe.mappaList[0].timeMachine 
		 * 
		 */
		timeMachineToShow: null,
		
		/**
		 * @property {Number} mapViewerRatio
		 * @private
		 * 
		 * 
		 */
		mapViewerRatio: null,
		
		/**
		 * @property {Number} [mapviewerWidth=0]
		 * @private
		 * 
		 * 
		 */
		mapviewerWidth: 0, 
		
		/**
		 * @property {Number} [mapviewerHeight=0]
		 * @private
		 * 
		 * 
		 */
		mapviewerHeight: 0,
		
		/**
		 * @property {Number} [mapviewerWidthWithRatio=0]
		 * @private
		 * 
		 * 
		 */
		mapviewerWidthWithRatio: 0,
		
		/**
		 * @property {Number} [mapviewerHeightWithRatio=0]
		 * @private
		 * 
		 * 
		 */
		mapviewerHeightWithRatio: 0,
		
		/** 
		 * @property {Array} [itemsList=[]]
		 * <pre>
		 * <br/>
		 * Esempio:<br/>
		 * 
		 * { tipo: '', url: '', styles: '', mappa: '', layer: '', formato: '', srid: '', testo: '' }
		 * 
		 * var itemList = [ { tipo: 'mapserver', url: "", styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto1954.map", layer: "FOTO1954", formato:"",	testo: "1954" },
	                 { url: "", styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto1978.map", layer: "FOTO1978", formato:"",	testo: "1978" },
	                 { tipo: 'mapserver', styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto1996.map", layer: "FOTO1996", formato:"",	testo: "1996" },
	                 { tipo: 'mapserver', url: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto2002.map", layer: "FOTO2002", formato:"",	testo: "2002" },
	                 { tipo: 'mapserver', url: "", styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto2003.map", layer: "FOTO2003", testo: "2003" },
	                 { tipo: 'mapserver', url: "", styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto2009.map", layer: "FOTO2009", formato:"",	testo: "2009" },
	                 { tipo: 'WMS', url: "http://geoserver.comune.prato.it/geoserver/wms", styles: "", mappa: "", layer: "comunepo:ortofoto2009", formato:"image/jpeg", srid:"EPSG:3003",	testo: "2009 geoserver" },
	                 { tipo: 'WMS', url: "http://web.rete.toscana.it/sgrwms/com.rt.wms.RTmap", styles: "", mappa: "", layer: "idsfondodtm50kcol", formato:"image/jpeg", srid:"EPSG:3003",	testo: "Hillshade Geoscopio" }  ];
	 		 * </pre>
		 * 
		 * {Object}[]
		 */
		itemsList: [],
		
		/**
		 * @method initComponent
		 * 
		 * 
		 */
		initComponent: function(){
			
			if (this.carouselConfig==null) this.carouselConfig = {};
			TolomeoExt.applyIfEmpty(this.carouselConfig, 
											{   interval: 3,
											    autoPlay: true,
											    showPlayButton: true,
											    pauseOnNavigate: true,
											    freezeOnHover: true,
											    transitionType: 'fade',
											    transitionEasing: 'fadeIn',    
											    navigationOnHover: false    
											});


			
			if (this.viewer) this.bindToViewer();
			if (this.paramsJS && this.itemsList.length==0) {
				// TODO gestire il caso nel quale la mappa selezionata non sia la 0 (del preset)
				this.itemsList = [];
				if (this.timeMachineToShow==null) {
					if (this.paramsJS.mappe.mappaList[0].timeMachine && this.paramsJS.mappe.mappaList[0].timeMachine.length>0) {
						this.itemsList = this.paramsJS.mappe.mappaList[0].timeMachine.layerList;
					}
				} else {
					this.itemsList = this.paramsJS.mappe.mappaList[0].timeMachineList[this.timeMachineToShow].layerList;
				}
			}
			this.callParent(arguments);
			
		},
		
		/**
		 * @method setMapViewerValues
		 * 
		 * 
		 * @param {Number} mapViewerRatio
		 * 
		 * 
		 * @param {Number} mapviewerWidth
		 * 
		 * 
		 * @param {Number} mapviewerHeight
		 * 
		 * 
		 */
		setMapViewerValues: function(mapViewerRatio, mapviewerWidth, mapviewerHeight) {
			
			if (mapViewerRatio)  this.mapViewerRatio  = mapViewerRatio;
			if (mapviewerWidth)  this.mapviewerWidth  = mapviewerWidth;
			if (mapviewerHeight) this.mapviewerHeight = mapviewerHeight;
			this.mapviewerWidthWithRatio  = Math.round(this.mapviewerWidth * ((this.mapViewerRatio) ? this.mapViewerRatio : 1));
			this.mapviewerHeightWithRatio = Math.round(this.mapviewerHeight * ((this.mapViewerRatio) ? this.mapViewerRatio : 1));
			this.calculateAutoOffset();
			this.autoOffset();
		}, 
		
		/**
		 * @method calculateAutoOffset
		 * 
		 * 
		 */
		calculateAutoOffset: function() {
			
			this.autoOffsetXAdjust= (this.mapViewerRatio) ? - this.mapviewerWidth/2 * (this.mapViewerRatio-1) : 0  ;
			this.autoOffsetYAdjust= (this.mapViewerRatio) ? - this.mapviewerHeight/2 * (this.mapViewerRatio-1) : 0  ;  
		}, 
		
		/**
		 * @method mapPanelSizeUpdate
		 * 
		 * 
		 */
		mapPanelSizeUpdate: function() {
			this.setMapViewerValues(null, this.viewer.getWidth(), this.viewer.getHeight());
		},
		
		/**
		 * @method getMapViewerValuesFromViewer
		 * 
		 * 
		 */
		getMapViewerValuesFromViewer: function() {
			
			this.mapViewerRatio =  this.viewer.pluginGetMapRatio();   // 1.5
			this.mapviewerWidth  = Math.round(this.viewer.pluginGetMapViewerWidth());
			this.mapviewerHeight = Math.round(this.viewer.pluginGetMapViewerHeight());
			this.mapviewerWidthWithRatio  =  Math.round(this.mapviewerWidth * ((this.mapViewerRatio) ? this.mapViewerRatio : 1));
			this.mapviewerHeightWithRatio = Math.round(this.mapviewerHeight * ((this.mapViewerRatio) ? this.mapViewerRatio : 1));
			
		},
		
		/**
		 * @method bindToViewer
		 * 
		 * 
		 * @param {Object} viewer
		 * 
		 * 
		 */
		bindToViewer: function(viewer) {
			var thisPanel=this;
			
			if (viewer) this.viewer = viewer;
			
			if (this.viewer) {
				// collegare ad un evento alla fine del quale siano disponibili i dati (postinit? afterrender?)
				var pos = this.viewer.getPosition();
				this.carouselFixedLeft = pos[0];
				this.carouselFixedTop  = pos[1];   
				
				this.getMapViewerValuesFromViewer();
				
				
				
				// registra evento nel caso cambi il layer selezionato nel layer switcher
				this.mon(this.viewer,'changebaselayer', 
									function() {
											this.getMapViewerValuesFromViewer();
											this.setMapViewerValues();
											}, this);
				
				// registrarsi per ricevere le modifiche di dimensioni del viewer
				this.mon(this.viewer, 'resize', this.mapPanelSizeUpdate, this);
				
				
				
				// TODO vedere funzione e contesto 
				this.mon(this.viewer, 'onMapMoveEnd', this.reloadItems, this);
			 	
			 	//this.on ('afterrender', function() {
			 	//this.viewer.on('move',  function() { alert('pippo'); /*this.setCarouselFixed*/}, this);
			 	

			 	this.on('draggableObjInitialized', 
			 				function(draggableObj) {
			 							
						 			draggableObj.dd.startDrag = draggableObj.dd.startDrag.createSequence(
																		function(){
																	
																			var pos = this.viewer.getPosition();
																			if ((this.carouselFixedLeft != pos[0]) || (this.carouselFixedTop  != pos[1])) {
																				var newCarouselFixedLeft = pos[0];
																				var newCarouselFixedTop  = pos[1];
																				thisPanel.setCarouselFixed(newCarouselFixedLeft, newCarouselFixedTop);	    
																			}
																		}, thisPanel);
									}, thisPanel);

			 
			 	
			 	
			}	
			
		},		
		
		/**
		 * @method loadItem
		 * <pre>
		 * Aggiunge un item alla lista. E' comunque possibile caricarla direttamente all'inizializzazione passando il parametro itemList.
		 * Esempio di utilizzo:
		 * 
		 * var itemList = [ { tipo: 'mapserver', url: "", styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto1954.map", layer: "FOTO1954", formato:"",	testo: "1954" },
	                 { url: "", styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto1978.map", layer: "FOTO1978", formato:"",	testo: "1978" },
	                 { tipo: 'mapserver', styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto1996.map", layer: "FOTO1996", formato:"",	testo: "1996" },
	                 { tipo: 'mapserver', url: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto2002.map", layer: "FOTO2002", formato:"",	testo: "2002" },
	                 { tipo: 'mapserver', url: "", styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto2003.map", layer: "FOTO2003", testo: "2003" },
	                 { tipo: 'mapserver', url: "", styles: "", mappa: "/usr1/test/vh/tolomeo/mapfiles/ortofoto2009.map", layer: "FOTO2009", formato:"",	testo: "2009" },
	                 { tipo: 'WMS', url: "http://geoserver.comune.prato.it/geoserver/wms", styles: "", mappa: "", layer: "comunepo:ortofoto2009", formato:"image/jpeg", srid:"EPSG:3003",	testo: "2009 geoserver" },
	                 { tipo: 'WMS', url: "http://web.rete.toscana.it/sgrwms/com.rt.wms.RTmap", styles: "", mappa: "", layer: "idsfondodtm50kcol", formato:"image/jpeg", srid:"EPSG:3003",	testo: "Hillshade Geoscopio" }
	                  ];
	
			timeMachinePnl =	new TolomeoExt.ToloTimeMachinePanel({
										viewer: tolomeoPnl.api.viewer,
										//itemsList: itemList,
										//carouselItems: ['1','2','3','4','5'],
										carouselConfig: {
											    interval: 3,
											    autoPlay: true,
											    showPlayButton: true,
											    pauseOnNavigate: true,
											    freezeOnHover: true,
											    transitionType: 'fade',
											    transitionEasing: 'fadeIn',    
											    navigationOnHover: false    
											}
										});
			
			for (var i=0; i<itemList.length; i++) {
				timeMachinePnl.loadItem(	itemList[i],
									(i==itemList.length-1)
								);
				}
				 	
			 var timeMachineWin = new Ext.Window({ title: "pp",  
						layout: 'fit',
						maximizable:true,
						collapsible:true,
						left:0, right:0,
						height: 200, width:200,
						autoScroll: true,
						renderTo: tolomeoPnl.api.viewer.body,
						items: [ timeMachinePnl
							] });
		 *</pre>
		 * map, layername, text,
		 * 
		 * @param {Object} item
		 * 
		 * 
		 * @param {Object} refresh
		 * 
		 * 
		 */
		loadItem: function(item, refresh) {
			//item
			this.itemsList.push(item);
			this.addImgItem ("" + Math.random(), 
							// map, layername
							this.viewer.pluginServerUrl(item, this.mapviewerWidthWithRatio, this.mapviewerHeightWithRatio), 
							item.testo, 
							refresh);
			
		},
		
		/**
		 * @method reloadItems
		 * svuota la lista degli item e la ricarica con gli stessi item, allo scopo di farli richiedere al server
		 * 
		 */
		reloadItems: function () {
		
			this.activeSlide =null;
			if (this.carousel) this.activeSlide = this.carousel.activeSlide;
			this.clearItems();
			var items = this.itemsList; 
			this.itemsList=[];
			
			var bDaSettareSlide = (this.carousel!=null && this.activeSlide!=null && this.activeSlide!=0);
			
			for (var i=0; i<items.length; i++) {
				this.loadItem( items[i], false); 	
			}
			this.refresh(this.activeSlide);
			/*if (bDaSettareSlide) {
				this.carousel.setSlide();
			}*/
			
		}
		
		
	});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * @class TolomeoExt.ToloTimeMachineMultiPanel
 * @extends Ext.Panel
 * Pannello ExtJs che implementa la funzionalità TimeMachine multipla
 * 
 * @param {Object} config
 * 
 * 
 * @param {Object} config.paramsJS
 * Oggetto i parametri contenuti nel file di preset.
 * 
 * @author Ing. Alessandro Radaelli
 */
Ext.define('TolomeoExt.ToloTimeMachineMultiPanel', {
	
		extend: 'Ext.Panel',

		/** 
		 * @property {Object} paramsJS
		 * 
		 * 
		 */
		paramsJS : null,
		
		
		/** 
		 * @property {TolomeoExt.ToloViewerOLPanel} viewer 
		 * 
		 * 
		 */
		viewer: null,
			
		/** 
		 * @property {Object} voices
		 * 
		 * 
		 */
		voices: null,
			
		/** 
		 * @property {Object} timeMachinePanels
		 * 
		 * 
		 */
		timeMachinePanels: null,
		
		/** 
		 * @property {Object} draggableParent
		 * 
		 * 
		 */
		draggableParent: null,
		
		/** 
		 * @method initComponent
		 * 
		 * 
		 */
		initComponent: function(){
			
			this.frame= false;
			
			this.timeMachinePanels = [];
			for (var i = 0; i<this.paramsJS.mappe.mappaList[0].timeMachineList.length; i++) {
				this.timeMachinePanels.push(null);
			}
			
			//this.tbar = { items: this.createMenuVoices() };
			//this.contextMenu = this.createContextMenus();
			
			this.layout='fit';
			this.callParent(arguments);
			
			//this.setDraggableObj(ownerCt);
			this.on('added',  function(thisComponent, ownerCt, index) { 
												if (ownerCt.draggable) this.draggableParent= ownerCt;
												this._layoutTmPanels(1);
												/*for (var i=0; i < this.timeMachinePanels.length; i++) {
													this.timeMachinePanels[i].setDraggableObj(this.draggableParent);
												}*/
										},  
										this, 
										{single: true});
			

		}, 
		
		/** 
		 * @method _layoutTmPanels
		 * 
		 * 
		 * @param {Object} tipoLayout
		 * 
		 * 
		 */
		_layoutTmPanels: function(tipoLayout) {
			
			switch (tipoLayout) {
			case 1: 
				var tabsContents = [];
				for (var i = 0; i<this.paramsJS.mappe.mappaList[0].timeMachineList.length; i++) {
					this.timeMachinePanels[i] = this.createNewTimeMachinePanel(i); 
					tabsContents.push({ title: this.paramsJS.mappe.mappaList[0].timeMachineList[i].nome,
										layout: 'fit',
										items: [this.timeMachinePanels[i]]});
				}
				
				//activeItem: 0,
				//
				//{ items: [{ text: 'aaa'}, ], { text: 'aaa'} }
				var tabs = new Ext.TabPanel({ activeItem: 0, items: tabsContents });
				this.add(tabs);
				this.doLayout();
				
				this.on('afterlayout', function() {
					for (var i=0; i < tabsContents.length; i++) {
						this.timeMachinePanels[i].calculateAutoOffset();
						this.timeMachinePanels[i].reloadItems();
					}
				}, this);
				
				//afterrender
				tabs.on('tabchange', function(tabpanel, tab) {
					var tm = tab.items.items[0];
					//for (var i=0; i < tabsContents.length; i++) {
					tm.setDraggableObj(this.draggableParent);
					tm.calculateAutoOffset();
					tm.reloadItems();
					
					//this.timeMachinePanels[i].setDraggableObj(this.draggableParent);
					//this.timeMachinePanels[i].calculateAutoOffset();
					//this.timeMachinePanels[i].reloadItems();
					//}
				}, this); //, {single:true}
				
				break;
			case 2: 
				break;
			
			}
		},
		
		/** 
		 * @method cambiaTimeMachine
		 * 
		 * 
		 * @param {Number} index
		 * 
		 * 
		 */
		cambiaTimeMachine: function(index){

			this.timeMachinePanels[index]=this.createNewTimeMachinePanel(index);
			
			this.removeAll(true);
			this.add(this.timeMachinePanels[index]);
			this.doLayout();
			this.timeMachinePanels[index].calculateAutoOffset();
			this.timeMachinePanels[index].reloadItems();
		},
		
		/** 
		 * @method createNewTimeMachinePanel
		 * 
		 * 
		 * @param {Object} timeMachineToShow
		 * 
		 * 
		 */
		createNewTimeMachinePanel: function(timeMachineToShow) {

			var pnl = new TolomeoExt.ToloTimeMachinePanel({
							aaaa: timeMachineToShow,
							viewer: this.viewer,
							paramsJS: this.paramsJS,
							cls: 'clsTimeMachinePanel',
							timeMachineToShow: timeMachineToShow,
							autoDraggableDetect: false
					});

			pnl.on('afterrender', 
					function() {
						var el = pnl.getEl();
						//pnl.getEl().on('contextmenu', function( e, t, o) { e.stopEvent(); this.contextMenu.showAt(e.getXY());}, this);

						if (this.draggableParent!=undefined && this.draggableParent!=null) {
							pnl.setDraggableObj(this.draggableParent);
						}
						
					}, this, {single: true});
			
			//this.on('added',  function(thisComponent, ownerCt, index) { this.setDraggableObj(ownerCt); },  this.pnl, {single: true});
			//pnl.calculateAutoOffset();
        	//pnl.reloadItems();
        	
			return pnl;
		}, 
		
		/** 
		 * @method createContextMenus
		 * 
		 * 
		 */
		createContextMenus: function() {
			var voices = this.createMenuVoices();
			var ctxMenu = new Ext.menu.Menu({
								items: voices
								//menu: {
								//		items: voices
								//	}
								});
			return ctxMenu;
		},
		
		/** 
		 * @method createMenuVoices
		 * 
		 * 
		 */
		createMenuVoices: function() {
			//if (this.voices!=null) return this.voices;
			
			this.voices = [];
			
			// Scelta timemachine
			var store = new Ext.data.JsonStore({
	        	//id: 0,
	        	fields: [
	        	         'nome', 'layerList'],
	        	 data: this.paramsJS.mappe.mappaList[0].timeMachineList
	        	 //[[1, 'item1'], [2, 'item2']]
	    	});
			this.cmbScelta = new Ext.form.ComboBox({
							store: store,
							//valueField: 'myId',
						    displayField: 'nome',
						    forceSelection: true,
						    editable: false,
						    autoSelect: true,
						    typeAhead: true,
						    triggerAction: 'all',
						    fieldLabel: ToloI18n.getMsg("ToloTimeMachineMultiPanel.cmbScelta"),
						    //lazyRender:false,
						    mode: 'local',
						    listeners: {
						    	select: { fn: function( combo, record, index) { this.cambiaTimeMachine(index)}, scope: this}
						    }
		
			});
			this.voices.push(this.cmbScelta);
			
			this.voices.push({
					//xtype: 'menuitem',
					text: ToloI18n.getMsg("ToloTimeMachineMultiPanel.layout"),
					menu: {
						items: [
								{
								 	checked: true, 	
									text: ToloI18n.getMsg("ToloTimeMachineMultiPanel.toolbar"),
									listeners: {
										click: { fn: function(thisBtn, e) { if (thisBtn.checked) {
																		this.getTopToolbar().hide();
																		//thisBtn.setChecked(false);
																	} else {
																		this.getTopToolbar().show();
																		//thisBtn.setChecked(true);
																	}},
												  scope: this
												}
									}
								}, '-', {
						        	text: ToloI18n.getMsg("ToloTimeMachineMultiPanel.singolo")
						        },{
						        	text: ToloI18n.getMsg("ToloTimeMachineMultiPanel.tab")
						        }]
					}
					
			});
			
			return this.voices;
			
		}
				
	});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Iframe in cui vengono caricate le risorse informative esterne.<br/>
 * ATTENZIONE: se questo pannello viene inserito in contenitori che sono collapsible ed hanno animCollapse=true ad ogni apertura e 
 * 	chiusura del pannello il contenuto dell'iframe viene ricaricato, o più precisamente viene ricaricata url se definita alla creazione, altrimenti resta vuoto.
 *  Questo comportamento è molto pericoloso in caso di compilazione di form ed editing, per evitarlo accertarsi che i contenitori "padri" collapsible abbiano <br/>
 *  
 * - animCollapse: false<br/>
 * - floatable : false <br/>	
				
 * @class TolomeoExt.ToloIFrame
 * @extends Ext.BoxComponent
 */
Ext.define('TolomeoExt.ToloIFrame', {

	extend: 'Ext.Component',
	alias: 'widget.tx_toloIFrame',

	/** 
	 * @property {String} [url='']
	 * url da caricare nell'iframe
	 * 
	 */
	url: '',
	
	/** 
	 * @property {String} [iFrameName='pannello']
	 * Nome dell'iframe da utilizzare poi come target
	 * 
	 */
	iFrameName: 'pannello',
	
	/** 
	 * @property {String} iFrameId
	 * Id dell'iframe da utilizzare per recuperare l'elemento
	 * 
	 */
	iFrameId: null,
	
	/** 
	 * @property {String} iFrameTagId
	 * 
	 * 
	 */
	iFrameTagId: null, 	 	 
	
	/** 
	 * @method initComponent
	 * 
	 * 
	 */
	initComponent: function() {		

	/* TODO PLUGIN????
		var initializeVisModePlugin = true;
		this.plugins = this.plugins || []; 
		
		// Se è stato passato uno specifico plugin lo aggiungo nell'array dei plugins prima 
		// di aggiungere quello per il VisibilityMode
		if(!(this.plugins instanceof Array)){
			var obj = this.plugins;
			this.plugins = [];
			this.plugins.push(obj);			
		}		
		
		// Controllo se il plugin è già stato passato da fuori
		for(var i=0; i < this.plugins.length; i++){
			if(this.plugins[i] instanceof Ext.ux.plugin.VisibilityMode){
				initializeVisModePlugin = false;
				break;
			}
		}
		
		if(initializeVisModePlugin && !Ext.isIE){
			this.plugins.push(new Ext.ux.plugin.VisibilityMode({ bubble : true }));
		}		
		*/

		this.iFrameTagId = this.iFrameId ? this.iFrameId : 'iframe-' + this.iFrameName;
		
		this.autoEl = {tag: 'iframe', id: this.iFrameTagId, name: this.iFrameName, frameBorder: 0, src: this.url};
		
		// Applico i default
		//TODO RIATTIVARE TolomeoExt.Vars.ApplyIfDefaults(this);		
		this.callParent(arguments);
		
		//this.on('beforecollapse', this.copyIFrame);
		//this.on('hide', this.copyIFrame);
		
		//this.on('expand', this.restoreIFrame);
		//this.on('show', this.restoreIFrame);
		
	},
	
	/** 
	 * @method loading
	 * 
	 * 
	 * @param {Object} config
	 * 
	 * 
	 */
	loading: function(config){
		var frame = top.frames[this.iFrameName];
		var message = null;
		var htmlTemplate = config.htmlTemplate || "<html><head></head><body><p style='{1}'>{0}</p></body></html>";
		
		if(config.url){
			frame.location.replace(config.url);
			if(config.message){
				message = config.message;
			}
		}else{
			message = config.message || ToloI18n.getMsg("ToloIFrame.caricamento");
		}
		if(message){
			frame.document.open();
			frame.document.write(String.format(htmlTemplate,message,config.style));
	    	frame.document.close();
		}
	},
	
	/** 
	 * @method replaceUrl
	 * 
	 * 
	 * @param {String} url
	 * 
	 * 
	 * @param {Object} loadingConfig
	 * 
	 * 
	 */
	replaceUrl: function(url,loadingConfig){
		if(!url) return;
		if(loadingConfig){
			this.loading(loadingConfig);
		}
		top.frames[this.iFrameName].location.replace(url);
	},
	
	/** 
	 * @method changeUrl
	 * 
	 * 
	 * @param {Object} loadingConfig
	 * 
	 * 
	 */
	changeUrl: function(loadingConfig){
		if(!url) return;
		if(loadingConfig){
			this.loading(loadingConfig);
		}
		top.frames[this.iFrameName].location.href = url;
	}
	
	/*
	copyIFrame: function() {
		//this.elCopy = Ext.get(this.iFrameTagId).dom;
		if (this.getEl().dom) this.elCopy = Ext.clone(this.getEl().dom);
		//this.saveState();
	},
	
	
	restoreIFrame: function() {
		//Ext.get(this.iFrameTagId).dom = this.elCopy;
		if (this.elCopy) this.getEl().dom = this.elCopy;
	}
	*/
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * @class TolomeoExt.ToloTOCInfo
 * @extends Ext.util.Observable
 * Inizialmente alimentato con la deserializzazione di TOCBean contiene lo stato della legenga ed i metodi per interagire con tale stato 
 * 
 */

Ext.define('TolomeoExt.ToloTOCInfo', {

	extend: 'Ext.util.Observable',
	
	/**
	 * @property {Object} presetLegenda
	 * 
	 * 
	 */
	presetLegenda: null,
	
	/**
	 * @property {Object} [CATEGORIESARRAYNAME="categories"]
	 * 
	 * 
	 */
	CATEGORIESARRAYNAME: "categories",

	/**
	 * @constructor TolomeoExt.ToloTOCInfo
	 * Create a new TolomeoExt.ToloTOCInfo
	 * 
	 * @param {Object} config
	 * La configurazione
	 *  
	 * @returns {TolomeoExt.ToloTOCInfo}
	 * A new TolomeoExt.ToloTOCInfo
	 * 
	 */
	constructor: function(config) {

		Ext.apply(this, config);
		this.callParent(arguments);
		
		
		this.addEvents("catTreeIdxUpdate");
		this.addEvents("layTreeIdxUpdate");
		
	},

	/**
	 * @method _getCategoryInfoPriv
	 * @private
	 * Metodo privato per lo scorrimento ricorsivo delle categorie
	 * 
	 * @param {Object} catInfo
	 * 
	 * 
	 * @param {Array} idxs
	 * 
	 * 
	 * @param {Object} catArrayName
	 * 
	 * 
	 */
	_getCategoryInfoPriv: function(catInfo, idxs, catArrayName) {
		
		if (idxs.length==1) return catInfo[catArrayName][idxs[0]];
		else {
			var idx = idxs.shift();
			return this._getCategoryInfoPriv(catInfo[catArrayName][idx], idxs, catArrayName);
		}
	},
	
	/**
	 * @method getCategoryInfo
	 * Metodo per recuperare le info della categoria a partire dall'indice (che è complesso nella forma 0/1/...)
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 */
	getCategoryInfo: function(catIdx) {
		
		var idxs = catIdx.split(this.TOCCATSEPARATOR);
		return 	this._getCategoryInfoPriv(this, idxs, this.CATEGORIESARRAYNAME);
	
	},
	
	/**
	 * @method getCategoryPresetInfo
	 * Metodo per recuperare le info della categoria contenute nel preset a partire dall'indice (che è complesso nella forma 0/1/...)M
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 */
	getCategoryPresetInfo: function(catIdx) {
		
		if (this.presetLegenda==null) return null;
		
		var idxs = catIdx.split(this.TOCCATSEPARATOR);
		return 	this._getCategoryInfoPriv(this.presetLegenda, idxs, "categoryList");
	},
	
	/**
	 * @method onEachCategory
	 * Metodo per il lancio della funzione fn all'interno del contesto scope per ogni categoria a partire da quella con indice startCatIdx. 
	 * Il metodo agisce in maniera ricorsiva se bRecurce non è definito o è true 
	 * La funzione fn viene chiamata passando gli argomenti cat ecatIdx  
	 * 
	 * @param {Object} fn
	 * 
	 * 
	 * @param {Object} scope
	 * 
	 * 
	 * @param {Object} startCatIdx
	 * 
	 * 
	 * @param {Object} bRecurse
	 * 
	 * 
	 */
	onEachCategory: function(fn, scope, startCatIdx, bRecurse) {
		var scopebuff = (scope) ? scope : this;
		var bRecurse = (bRecurse!=undefined && bRecurse !=null) ?  bRecurse : true;
		
		if (!startCatIdx) {
			if (this[this.CATEGORIESARRAYNAME].length!=0) {
				for (var i=0; i<this[this.CATEGORIESARRAYNAME].length; i++) {
					this.onEachCategory(fn, scope,""+i, bRecurse);
				}
				return;
			} else {
				return;
			}
		} 
		
		var scIdx = startCatIdx;
		
		var sc = this.getCategoryInfo(startCatIdx);

		fn.call(scope, sc, scIdx);
		 
		// categorie annidate
		if (bRecurse && sc.categories) {
			for (var i=0; i<sc.categories.length; i++) {
				var scIdxBuff = scIdx + this.TOCCATSEPARATOR + i;
				this.onEachCategory(fn, scope, scIdxBuff);
			}
		}
	},
	
	/**
	 * @method onEachLayer
	 * Metodo per il lancio della funzione fn all'interno del contesto scope per ognilayer contenuto in ogni categoria a partire da quella con indice startCatIdx. 
	 * Il metodo agisce in maniera ricorsiva se bRecurce non è definito o è true.
	 * La funzione fn viene chiamata passando gli argomenti cat, lay, catIdx e layIdx 
	 * 
	 * @param {Object} fn
	 * 
	 * 
	 * @param {Object} scope
	 * 
	 * 
	 * @param {Object} startCatIdx
	 * 
	 * 
	 * @param {Object} bRecurse
	 * 
	 * 
	 */
	onEachLayer: function(fn, scope, startCatIdx, bRecurse) {
		
		this.onEachCategory(
			function(cat, catIdx) {
				if (cat.layers) {
					for (var i=0; i<cat.layers.length; i++) {
						fn.call(scope, cat, cat.layers[i], catIdx, i);
					}
				}
			},
			this,
			startCatIdx,
			bRecurse
		);
		
	},
	
	/**
	 * @method getParentCategoryIdx
	 * Metodo per ottenere l'indice della categoria padre 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 */
	getParentCategoryIdx: function(catIdx) {
		
		if (!catIdx) return "";
		
		var idx = catIdx.lastIndexOf(this.TOCCATSEPARATOR);
		
		if (idx==-1) return "";
		else {
			return catIdx.substring(0, idx);
		}
		
	},
	
	/**
	 * @method onEachParentCategory
	 * Metodo per il lancio della funzione fn all'interno del contesto scope per ogni categoria padre a partire da quella con indice startCatIdx. 
	 * Il metodo agisce in maniera ricorsiva se bRecurce non è definito o è true.
	 * La funzione fn viene chiamata passando gli argomenti cat, catIdx  
	 * 
	 * @param {Object} fn
	 * 
	 * 
	 * @param {Object} scope
	 * 
	 * 
	 * @param {Object} startCatIdx
	 * 
	 * 
	 */	
	onEachParentCategory: function(fn, scope, startCatIdx) {
		
		var parentIdx = this.getParentCategoryIdx(startCatIdx);
		while (parentIdx!="") {
			var cat = this.getCategoryInfo(parentIdx);
			fn.call(scope, cat, parentIdx);
			parentIdx = this.getParentCategoryIdx(parentIdx);
		}
		
	},
	
	/**
	 * @method areAllParentCatChecked
	 * Metodo che verifica se tutte le categorie padre hanno il flag checked==true
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 */
	areAllParentCatChecked: function(catIdx) {
		var retObj1 = { bAllChecked: true };
		this.onEachParentCategory(
				function(parentCat, parentCatIdx) {
					if (!parentCat.checked) this.bAllChecked = false;
				}, 
				retObj1,
				catIdx
		);
		return retObj1.bAllChecked;
	},
	
	/**
	 * @method setLayerNeedRequestVisibleData
	 * Metodo per settare a value il flag needRequestVisibleData del layer individuato dalla coppia catIdx, layIdx 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 * @param {Object} value
	 * 
	 * 
	 */
	setLayerNeedRequestVisibleData: function(catIdx, layIdx, value) {
		this.getCategoryInfo(catIdx).layers[layIdx]._needRequestVisibleData = value;
	},
	
	/**
	 * @method getLayerNeedRequestVisibleData
	 * Metodo recuperare il valore del needRequestVisibleData del layer individuato dalla coppia catIdx, layIdx 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 */
	getLayerNeedRequestVisibleData: function(catIdx, layIdx) {
		var val = this.getCategoryInfo(catIdx).layers[layIdx]._needRequestVisibleData;
		
		return (val!=undefined && val!=null) ? val : false;
	},
	
	/**
	 * @method getLayerBoundingBox
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 */
	getLayerBoundingBox: function(catIdx, layIdx) {
		var layer = this.getCategoryInfo(catIdx).layers[layIdx];		
		
		if (layer.bboxMinX!=0 && layer.bboxMinY!=0 && layer.bboxMaxX!=0 && layer.bboxMaxY != 0) {
			var bbox = new BBox(layer.bboxMinX, layer.bboxMinY, layer.bboxMaxX, layer.bboxMaxY);
			return bbox
			
		} else {
			return null;
		}
	}, 
	
	
	/**
	 * @method getCategoryBoundingBox
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 */
	getCategoryBoundingBox: function(catIdx) {
		
		var bboxTot = null;
		
		this.onEachLayer( 
				function(cat, lay, catIdx, layIdx) {
					var bbox = this.getLayerBoundingBox(catIdx, layIdx);
					if (bbox!=null) {
						if (bboxTot==null) {
							bboxTot = new BBox(bbox.left,bbox.bottom,bbox.right,bbox.top);
						} else { 
							bboxTot.bottom = Math.min(bboxTot.bottom, bbox.bottom);
							bboxTot.left = Math.min(bboxTot.left, bbox.left);
							bboxTot.top = Math.max(bboxTot.top, bbox.top);
							bboxTot.right = Math.min(bboxTot.right, bbox.right);
						}
					}
				},
				this, 
				catIdx, true);
		
		return bboxTot;
		
	}, 
	
	/**
	 * @method getBoundingBox
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 */
	getBoundingBox: function(catIdx, layIdx) {
		if (layIdx==null) return this.getCategoryBoundingBox(catIdx);
		else return this.getLayerBoundingBox(catIdx, layIdx);
	}, 
	
	/**
	 * @method getServer
	 * 
	 * 
	 * @param {Object} serverId
	 * 
	 * 
	 */
	getServer: function (serverId) {
		return this.server[serverId]; 
	},
	
	/**
	 * @method searchLayerInfo
	 * 
	 * 
	 * @param {Object} serverID
	 * 
	 * 
	 * @param {Object} name
	 * 
	 * 
	 */
	searchLayerInfo: function(serverID, name) {
		var retVal = null;
		
		this.onEachLayer( 
				function(cat, lay, catIdx, layIdx) {
					if(retVal) return;
					// TODO SERVER IMPLICITO
					var serverIdToCompare = (serverID == "INLINESERVERID") ? "" : serverID;  
										
					if (lay.name==name && (!serverID || lay.serverID==serverIdToCompare)) {
						retVal = lay;
					}						
					
				},
				this);
				
		return retVal;
	}, 
	
	/**
	 * @method searchLayerInfoByDesc
	 * 
	 * 
	 * @param {Object} desc
	 * 
	 * 
	 * @param {Object} itemType
	 * 
	 * 
	 */
	searchLayerInfoByDesc: function(desc, itemType) {
		var retVal = null;
		
		this.onEachLayer( 
				function(cat, lay, catIdx, layIdx) {
					if (lay.descr == desc && lay.itemType == itemType) {
						retVal = lay;
					}
				},
				this);
				
		return retVal;
	}, 
	
	/**
	 * @method addCategory
	 * Aggiunge una categoria nella posizione indicata dai parametri.
	 * 
	 * @param {Object} catInfo
	 * Categoria da aggiungere
	 * 
	 * @param {Object} addPointCatIdx
	 * categoria prima o dopo della quale va aggiunta la roba
	 * 
	 * @param {Object} bBefore
	 * indica se aggiungere prima o dopo 
	 * 
	 */
	addCategory: function(catInfo, addPointCatIdx, bBefore) {
		
		// Cerca addPoint
		var addPoint = this.getCategoryInfo(addPointCatIdx);
		
		// Cerca il parent
		var addPointParentIdx = this.getParentCategoryIdx(addPointCatIdx);
		var addPointParent = null;
		
		// Se parent == null sono sul primo livello
		if (addPointParentIdx == "") {
			addPointParent = this;
		} else {
			addPointParent = this.getCategoryInfo(addPointParentIdx);
		}

		var c = (addPointParent.catTreeIdx) ? addPointParent.catTreeIdx : ""; 
				
		// Calcolo la posizione di inserimento
		var idxs = addPointCatIdx.split(this.TOCCATSEPARATOR);
		var pos = parseInt(idxs[idxs.length-1]) + ((bBefore) ? 0 : 1);
		
		// Aggiorno indice cat
		catInfo.catTreeIdx = c + ((c!="") ?  this.TOCCATSEPARATOR : "") + pos; 
		
		//Inserisco nella giusta posizione
		if (pos > 0) {
			addPointParent.categories.splice(pos, 0, catInfo);
		} else {
			addPointParent.categories.unshift(catInfo);
		}
		
		// rinumero indici
		this.updateIdxs(addPointParent, c);
		
	},
	
	/**
	 * @method updateIdxs
	 * Aggiorna tutti gli indici catTreeIdx e layTreeIdx.
	 * 
	 * @param {Object} cat
	 * categoria dalla quale iniziare ad aggiornare gli indici
	 * 
	 * @param {Object} newCatTreeIdx
	 * nuovo valore di treeIdx
	 * 
	 */
	updateIdxs: function(cat, newCatTreeIdx) {
		
		if (newCatTreeIdx!="") {
			// Aggiorna questa categoria
			var oldCatTreeIdx = cat.catTreeIdx;
			cat.catTreeIdx = newCatTreeIdx;
			if (oldCatTreeIdx != newCatTreeIdx) {
				this.fireEvent("catTreeIdxUpdate", cat.catId, oldCatTreeIdx, newCatTreeIdx);
			}
		
			// Aggiorna tutti i layer
			var layArray = cat.layers;
			if (layArray) {
				for (var i=0; i<layArray.length; i++) {
					layArray[i].catTreeIdx = newCatTreeIdx;
					if (oldCatTreeIdx != newCatTreeIdx) {
						// Utilizza i il nuovo catTreeIdx perchè ha già rinumerato la categoria con l'evento precedente
						this.fireEvent("layTreeIdxUpdate", layArray[i].layId, oldCatTreeIdx, layArray[i].layTreeIdx, newCatTreeIdx, layArray[i].layTreeIdx);
					}
				}
			}
		} 
		
		// Cicla sulle categorie figlie
		var catArray = cat.categories;
		if (catArray) {
			for (var i=0; i<catArray.length; i++) {
				var newPrefix = newCatTreeIdx + ((newCatTreeIdx != "") ? this.TOCCATSEPARATOR : "") + i ;				
				this.updateIdxs(catArray[i],newPrefix);		
			}
		}
		
	},
	
	/**
	 * @method addLayer
	 * Aggiunge un layer nella posizione indicata dai parametri.
	 * 
	 * @param {Object} layInfo
	 * Layer da aggiungere
	 * 
	 * @param {Object} addPointCatIdx
	 * Indice della categoria nella quale viene aggiunto il layer 
	 * 
	 * @param {Object} addPointLayIdx
	 * Indice layer prima o dopo del quale aggiungere il nuovo layer
	 * 
	 * @param {Object} bBefore
	 * indica se aggiungere prima o dopo
	 * 
	 */
	addLayer: function(layInfo, addPointCatIdx, addPointLayIdx, bBefore) {
		// Cerca addPoint
		var addPoint = this.getCategoryInfo(addPointCatIdx);
		
		// Calcolo la posizione di inserimento
		var pos;
		if (addPointLayIdx) {
			pos = parseInt(addPointLayIdx) + ((bBefore) ? 0 : 1);
		} else { // se non è definito addPointLayIdx inserire come primo elemento della categoria
			pos = addPoint.layers.length-1;
		}
		
		// Aggiorno indice cat
		layInfo.catTreeIdx = addPointCatIdx; 
		layInfo.layTreeIdx = "" + pos;
		
		//Inserisco nella giusta posizione
		if (pos > 0) {
			addPoint.layers.splice(pos, 0, layInfo);
		} else {
			addPoint.layers.unshift(layInfo);
		}
		
		// rinumero indici
		
		for (var i=0; i<addPoint.layers.length; i++) {
			var l = addPoint.layers[i];
			var oldLayTreeIdx = l.layTreeIdx
			l.layTreeIdx = i;
			if (oldLayTreeIdx!=i) { 
				this.fireEvent("layTreeIdxUpdate", l.layId, addPointCatIdx, oldLayTreeIdx, addPointCatIdx, l.layTreeIdx);
			}
		}
	},
	
	/**
	 * @method JSONEncodeInfo
	 * 
	 * 
	 * @param {Object} catIdx
	 * 
	 * 
	 * @param {Object} layIdx
	 * 
	 * 
	 */
	JSONEncodeInfo: function(catIdx, layIdx) {
		
		var info = {
			TOCCATSEPARATOR: this.TOCCATSEPARATOR,
			categories: this.categories,
			server: this.server
		}
		
		return Ext.JSON.encode(info);
	}
	
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/
// @include "../tolomeoExt/include.js"

Ext.namespace("TolomeoExt");


/**
 * @class TolomeoExt.ToloIIPPanel
 * @extends Ext.Panel
 * Pannello per contenere un viewer per IIPImage. In funzione del valore della variabile di configurazione tipo sono utilizzati: <br/>
 * tipo='iipzoom'
 * tipo='iipmooviewer'
 * in caso di utilizzo di iipmooviewer includere i seguenti css
 * <pre>
 * <link rel="stylesheet" type="text/css" media="all" href="<%=tolomeoServer %>/js/ext/iipmooviewer-2.0/css/iip.compressed.css">
 * <!--[if lt IE 10]>
 * <link rel="stylesheet" type="text/css" media="all" href="<%=tolomeoServer %>/js/ext/iipmooviewer-2.0/css/ie.compressed.css" />
 * <![endif]-->
 * </pre>
 * <br />
 * Esempio di utilizzo
 * 
 *  <pre>
   new TolomeoExt.ToloIIPPanel({ ///TolomeoProxyServlet?
	    	title: 'Anteprima',
			proxy: '/tolomeobinj/TolomeoProxyServlet?',
			// TODO generalizzare
			iipserver:  "http://localhost:80/fcgi-bin/iipsrv.fcgi",
			iipimage:  "/opt/grandeformato/vips.tif",
			copyright: "copyright or information message",
			tipo: 'iipzoom', //'iipzoom' 'iipmooviewer'
			api: this.api,
			
			region: 'east',
			width: 250,
			split:true,
			collapsible:true,
			renderTo: 'mydiv'
	    });
	    
	</pre>
 *
 */
Ext.define('TolomeoExt.ToloIIPPanel', {

	extend: 'Ext.Panel',
 

	/** 
	 * @cfg {String} TOLOMEOServer
	 * 
	 * 
	 */
	TOLOMEOServer: null,

	/** 
	 * @cfg {String} TOLOMEOContext
	 * 
	 * 
	 */
	TOLOMEOContext: null,
	
	/** 
	 * @cfg {String} TOLOMEOStaticRoot
	 * 
	 * 
	 */	
	TOLOMEOStaticRoot: null, 
	
	/**
	 * @cfg {Object} viewerPanel
	 * 
	 * 
	 */
	viewerPanel: 	null, 

	/**
	 * @cfg {String} iipserver
	 * Indirizzo del server IIPImage (per esempio "http://localhost/fcgi-bin/iipsrv.fcgi" )  
	 * 
	 */
	iipserver: 		null,
	
	/**
	 * @cfg {String} iipimage
	 * Immagine da caricare all'avvio. Per esempio "/opt/grandeformato/vips.tif"  
	 * 
	 */
	iipimage: 		null,
	
	/**
	 * @cfg {String} copyright
	 * testo del copyright da inserire nell'immagine  
	 * 
	 */
	copyright: 		"",
	
	/**
	 * @cfg {String} proxy
	 * Il server iipimage deve essere raggiunto dal javascript, per evitare problemi di Cross Domain Ajax Call 
	 * potrebbe essere necessario impostare un proxy. E' possibile utilizzare la servlet di proxy fornita con tolomeo impostando questo valore a
	 * '/tolomeobinj/TolomeoProxyServlet?' ed inserendo il server iipimage nel file tolomeo.properties in PROXY.HOSTNAME_WHITELIST   
	 * N:B: Questa impostazione è valida solo per visualizzatore iipmooviewer
	 * 
	 */
	proxy:			null,
	
	/**
	 * @cfg {String} api
	 * Oggetto API di tolomeo  
	 * 
	 */
	api: 			null, 
	
	/**
	 * @cfg {String} tipo
	 * tipo di viewer. Sono possibili i valori iipzoom (visualizzatore flash) e iipmooviewer (visualizzatore HTML5 e javascript)  
	 * 
	 */
	tipo: 			'iipzoom',
	
	/**
	 * @cfg {String} iipviewerId
	 * 
	 * 
	 */
	iipviewerId: null,
	
	/**
	 * @cfg {String} iipmooviewer
	 * 
	 * 
	 */
	iipmooviewer: null, 
	
	/**
	 * @method initComponent
	 * 
	 * 
	 */
	initComponent: function(){
		
		var thisPanel=this;
		this.layout = 'fit';
		
		TolomeoExt.Vars.ApplyIfDefaults(this);	
		
		this.callParent(arguments);
		
		this.iipviewerId=this.id+'-iipviewer';
		
        this.viewerPanel = new Ext.Panel({	
        	style: 'z-index:0;',
			layout: 'fit',	
			bodyBorder: false,
			border: false,
			anchor: '100% 100%',
			html: '<div id="' + this.iipviewerId + '" style="width:99%;height:99%;margin-left:auto;margin-right:auto" />', 
			monitorResize: true
		});
        this.add(this.viewerPanel);
		
		this.on('afterlayout', function() { 
			this.showViewer();
		}, this, {single: true}); 

		this.doLayout();

    },
    
    /**
     * @method showViewer
     * @private
     * 
     * 
     */
    showViewer: function() {
		
    	var iipopt = {
			server: this.iipserver, // this.iipserver,
			image: this.iipimage,
			credit: this.copyright
    	};
    	
    	var flashOnlyOpts = {
    		navigation: true
    	}

    	var iipmoo1OnlyOpts = {
    	   zoom: 1,
    	   render: 'random',
           showNavButtons: true,
			//prefix: this.TOLOMEOServer + this.TOLOMEOStaticRoot + 'js/ext/iipmooviewer-2.0/images/',
           prefix: this.TOLOMEOServer + '/js/ext/iipmooviewer-2.0/images/',
			enableFullscreen: true
    	}
    	
		var params = {
			scale: "noscale",
			bgcolor: "#000000",
			allowfullscreen: "true",
			allowscriptaccess: "always"
		}
    	
		switch (this.tipo){
			case 'iipzoom':
				Ext.apply(iipopt, flashOnlyOpts);
				
				this.api.lazyLoadScript('swfobject',
						function() { this.embedIIPZoom(Ext.apply(iipopt, flashOnlyOpts) , params);}, 
						function(){
							Ext.Msg.alert(ToloI18n.getMsg("ToloIIPPanel.problemaLibrerie.alert.title"),
										ToloI18n.getMsg("ToloIIPPanel.problemaLibrerie.alert.msg"));},
						this
					);
				break;
			case 'iipmooviewer':
				iipopt.server = ((this.proxy!=null && this.proxy!="") ? this.proxy : "") + iipopt.server;
				Ext.apply(iipopt, iipmoo1OnlyOpts);
				
				this.api.lazyLoadScript(['mootoolscore145', 'mootoolsmore1401', 'iipmooviewer20'],
						function() { this.embedIIPMooviewer(iipopt); }, 
						function(){
							Ext.Msg.alert(ToloI18n.getMsg("ToloIIPPanel.problemaLibrerie.alert.title"),
										ToloI18n.getMsg("ToloIIPPanel.problemaLibrerie.alert.msg"));},
						this
					);
				break;
		}
    },
    
    /**
     * @method setAndShowNewImg
     * Imposta nuova immagine, server e copyright e visualizza
     * 
     * @param {String} iipimage
     * 
     * 
     * @param {String} iipserver
     * 
     * 
     * @param {String} copyright
     * 
     * 
     */
    setAndShowNewImg: function (iipimage, iipserver, copyright) {
    	
    	if (iipimage && iipimage!="") this.iipimage=iipimage;
    	if (iipserver && iipserver!="") this.iipserver=iipserver;
    	if (copyright && copyright!="") this.copyright=copyright;
    	
    	this.showViewer();
    	
    },
    
    /**
     * @method embedIIPMooviewer
     * @private
     * 
     * 
     * @param {Object} opt
     * 
     * 
     */
    embedIIPMooviewer: function(opt){
    	
        if (this.iipmooviewer!=null) {
        	// NB La versione iipmooviewer 2.0 beta utilizzata non ha metodo per cambiare immagine, quindi mi sono inventato questo metodo
        	this.viewerPanel.un('resize', this.iipmooviewer.reflow, this.iipmooviewer);
        	this.iipmooviewer.container.getChildren().each( function(el, i) { el.destroy(); } );
        } 
        this.iipmooviewer = new IIPMooViewer( this.iipviewerId, opt);
    	this.iipmooviewer.load();
    	this.viewerPanel.on('resize', this.iipmooviewer.reflow, this.iipmooviewer);

    },
    
    /**
     * @method embedIIPZoom
     * @private
     * 
     * 
     * @param {Object} opt
     * 
     * 
     * @param {Object} params
     * 
     * 
     */
    embedIIPZoom: function(opt, params){	
    	swfobject.embedSWF(this.TOLOMEOServer + this.TOLOMEOStaticRoot + "swf/iipzoom/IIPZoom.swf",this.iipviewerId, "100%", "100%", "9.0.0",this.TOLOMEOServer + this.TOLOMEOStaticRoot +"swf/iipzoom/expressInstall.swf", opt, params); 
    	//swfobject.embedSWF(this.TOLOMEOServer + "/swf/iipzoom/IIPZoom.swf",this.iipviewerId, "100%", "100%", "9.0.0",this.TOLOMEOServer +"/swf/iipzoom/expressInstall.swf", opt, params);
    }
	
});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.define('TolomeoExt.ToloLayerViewerAggregation', {

	extend: 'Ext.util.Observable',

	layers: null,
	tilesMultiple: null,
	overlay: null,
	SRID: null,
	units: null,
	mostraInLegenda: null,
	layerOptions: null,
	imagetype: null,
	server: null,
	checked: null,
	opacity: null,
	
	constructor: function(config) {
			
		if (config==undefined) config={};
		Ext.applyIf(config, { layers: [] });
		Ext.apply(this, config);
		
		this.callParent(arguments);
		
	}
	

});

function toloServerMappe(server) {
	
	/* 
	this.id						= null;
	this.nome 					= null;
	this.typeDescription       	= "Mapserver";
	this.typeCode             	= 0;
	this.nomeCredenziale   		= null;
	this.allowServerConnection 	= false;
	this.url          		  	= null;
	this.serverOpts				= null;
	*/
	if (server!=null) {
		Ext.apply(this, server);
	}
	
}

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.define('TolomeoExt.ToloMapDefinition', {

	extend: 'Ext.util.Observable',
	
	/**
	 * {Array} array contenete oggetti toloLayerViewerAggregation 
	 */
	layerAggregations: null,
	
	constructor: function(config) {
		
		if (config==undefined) config={};
		Ext.applyIf(config, { layerAggregations: [] });
		Ext.apply(this, config);
		this.callParent(arguments);
		//TolomeoExt.ToloMapDefinition.superclass.constructor.call(this, config);
		
	},
	
	addLayerAggregation: function(layerAggregation, index) {
		
		if (index==undefined || index==null) {
			layerAggregation.nPluginLayer=this.layerAggregations.length;
			this.layerAggregations.push(layerAggregation);
		} else {
			layerAggregation.nPluginLayer=index;
			this.layerAggregations[index] = layerAggregation;
		}
	
	},
	
	getLayerAggregation: function(index) {
		return this.layerAggregations[index];
	},
	
	getLayerAggregationCount: function() {
		return this.layerAggregations.length;
	},
	
	reverseLayerAggregationsOrder: function() {
		var buff = [];
		
		for (var i=0; i<this.getLayerAggregationCount(); i++) {
			buff[i] = this.getLayerAggregation(i).nPluginLayer;
		}
		this.layerAggregations.reverse();
		
		for (var i=0; i<this.getLayerAggregationCount(); i++) {
			this.getLayerAggregation(i).nPluginLayer = buff[i];
		}
	},
	
	/**
	 * Cerca quale layer aggregation contiene il layer individuato dagli indici catIdx, layIdx
	 */
	whichLayerAggregationContains: function (catTreeIdx, layTreeIdx) {
		
		for (var i=0; i<this.getLayerAggregationCount(); i++) {
			var lag = this.getLayerAggregation(i);
			for (var j=0; j < lag.layers.length; j++ ) {
				var layer = lag.layers[j];
				if (layer.catTreeIdx==catTreeIdx && layer.layTreeIdx==layTreeIdx) return lag;
			}
		}
		
		return null;
	},
	
    whichLayerAggregationContainsNPluginLayer: function (nPluginLayer) {
		
		for (var i=0; i<this.getLayerAggregationCount(); i++) {
			var lag = this.getLayerAggregation(i);
			if (lag.nPluginLayer==nPluginLayer) return lag;
		}
		
		return null;
	}

});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * @class TolomeoExt.ToloGenericWindow
 * @extends Ext.Window
 *
 */
Ext.define('TolomeoExt.Window', {

	extend: 'Ext.Window',
	alias: 'widget.tolomeoExtWindow',
	
	/**
	 * @method constructor
	 * 
	 * 
	 */
	constructor: function(config){		
		this.callParent(arguments);
		
		var clearCls = 'clearCSS';
		if(!this.cls){
			this.cls = clearCls;
		} else {
			if(this.cls.indexOf(clearCls) == -1){
				this.cls += ' ' + clearCls;
			}
		}					
	}
	
	
	
});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


Ext.define('TolomeoExt.ToloWMSExplorerPanel', {

	extend: 'Ext.Panel',
	
	paramsJS: null,
	
	initComponent: function(){
		//Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);	
		/*
		this.layout= {
	        type: 'vbox',
	        align: 'center'
	    };
		*/
		
		var me = this;
		this.frame = false;
		this.border = false;
		
		this.layout = 'border';
		/*
		this.bbar = [
			  { xtype: 'button', text: 'Button 1' }
			];
		*/
		
		/**
		 * @event addLayer
		 * Lanciato quando viene premuto il tasto "Aggiungi layer"
		 * Viene passato array  così composto
		 * [{ url: url del wms, name: nome del layer }.... ]
		 */
		this.addEvents('addLayer');
		
		/**
		 * @event closePressed
		 * Lanciato quando viene premuto il tasto "Chiudi"
		 */
		this.addEvents('closePressed');
		
		this.buttonAlign = 'center';
		
		this.btnAddLayer = Ext.create('Ext.Button',{
								text: ToloI18n.getMsg("ToloWMSExplorerPanel.btnAddLayer"),
								handler: function() {
									var selected = me.grid.getView().getSelectionModel().getSelection();
									var retVal = [];
									var url = me.cmbServerList.getValue(); 
									for (var i=0; i< selected.length; i++) {
										var l = { url: url,
												  name: selected[i].get('name') };
										retVal.push(l);
									}
									me.fireEvent('addLayer', retVal );
								}
		});
		
		this.buttons = [
			  this.btnAddLayer, //, margin: '0 10 5 0' 
			  { text: ToloI18n.getMsg("ToloWMSExplorerPanel.btnChiudi"),
			    handler: function() {
			    		me.fireEvent('closePressed');
			    	}
			    }
			];
		/*
		this.dockedItems = [{
			    xtype: 'panel',
			    dock: 'bottom',
			    items: [
			        { xtype: 'button', text: 'Button 1' }
			    ]
			}]
		*/

		this.callParent(arguments);
		
		var proxy = TolomeoExt.ToloCrossAjaxUtil.getProxy(null, this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxWMSExplorerServlet');
		
		/*proxy.extraParams= {
	       		format:"ext",
	        	idCampo: i,
	        	SRID: this.paramsJS.mappe.SRID,
	        	withGeom: this.suggestWithGeom
	        };*/
			
		var ds = Ext.create('Ext.data.JsonStore',{
		        proxy: proxy
				//autoLoad: true
		        /*idCampo: i,
				listeners: {
					beforeload: {
						fn: function(store, options) {
							return me.setAutoCompleteBaseParams(store, options);  
						}
					},
					load: {
						fn: function(store, records, options) {
							store.sort('descriptionSuggest'+store.idCampo,'ASC');
						}
					}
				}*/
			});
		var a = new TolomeoExt.ToloCrossAjax();
		proxy.on('exception', a.storeException);
		
		var data = (this.paramsJS.layOut.WMSExplorer.serverWMSList) ? this.paramsJS.layOut.WMSExplorer.serverWMSList : [] ;
		
		if (this.paramsJS.layOut.WMSExplorer.includeMapServers) {
			// Aggiunge i server della mappa
			var s = this.paramsJS.serverPool.serverList;
			
			for (var i=0; i<s.length; i++) {
				var serv = s[i];
				if (serv.showInWMSExplorer) {
					data.push ({nome: serv.nome, url: serv.url});
				}
			}
		}
		
		var serverStore = Ext.create('Ext.data.Store', {
		    fields: ['nome', 'url'],
		    data : data
		});

		this.cmbServerList = Ext.create('Ext.form.ComboBox', {
		    fieldLabel: ToloI18n.getMsg("ToloWMSExplorerPanel.cmbServerList.lbl"),
		    emptyText: ToloI18n.getMsg("ToloWMSExplorerPanel.cmbServerList.empty"),
		    //forceSelection: true,
		    labelWidth: 75,
		    store: serverStore,
		    queryMode: 'local',
		    displayField: 'nome',
		    valueField: 'url',
		    //name: 'serverUrl',
			listConfig: {
				    itemTpl: "<b><u>{nome}</u></b><br />{url}"
				},
			prevValue: null,
			changeServer: function() {
				if (this.prevValue!=this.getValue()) {
					ds.load({params: { serverUrl: this.getValue() }});
					this.prevValue = this.getValue();
     			}
			},
    		listeners:{    			
         		'select': function() {
		         			this.changeServer();
         				  },
         		'blur': function() {
         					this.changeServer();
         				},
         		specialkey: function(field, e){
	                    // e.HOME, e.END, e.PAGE_UP, e.PAGE_DOWN,
	                    // e.TAB, e.ESC, arrow keys: e.LEFT, e.RIGHT, e.UP, e.DOWN
	                    if (e.getKey() == e.ENTER) {
	                        //var form = field.up('form').getForm();
	                        //form.submit();
	                    	this.changeServer();
	                    }
                	}
    			}
    			
			});
			
		this.filterPanel = Ext.create('Ext.form.Panel', {
											//title: 'Filtro',
											bodyPadding: 10,
											layout: 'anchor',
										    defaults: {
										        anchor: '100%'
										    },
											collapsible: false,
											collapsed: false,
											frame: false,
											region: 'north',
											height: 70,
											items: [this.cmbServerList,
													{
														xtype: 'trigger',
														triggerCls : Ext.baseCSSPrefix + 'form-search-trigger',
														fieldLabel: ToloI18n.getMsg("ToloWMSExplorerPanel.filterPanel"),
														labelWidth: 40,
													    onTriggerClick: function() {
													        //Ext.Msg.alert('Status', 'You clicked my trigger!'+this.getValue());
													        me.applicaFiltro(this.getValue());
													    }
													}]
											
											});
		
											
		this.add(this.filterPanel);											
											
		this.grid = Ext.create('Ext.grid.Panel', {
							region: 'center',
							frame: false,
							store: ds,
							enableTextSelection: true,
							columns: [
							    { 	text: ToloI18n.getMsg("ToloWMSExplorerPanel.grid.titolo"),
							    	dataIndex: 'title',
							    	renderer: function(value, metadata) {
											        metadata.style = 'white-space: normal;';
											         return value;
											 }
							    },
							    { 	text: ToloI18n.getMsg("ToloWMSExplorerPanel.grid.desc"), 
							    	dataIndex: 'abstract', 
							    	flex: 4,
							    	renderer: function(value, metadata) {
											        metadata.style = 'white-space: normal;';
											         return value;
											 }
 								},
							    { text: ToloI18n.getMsg("ToloWMSExplorerPanel.grid.scalamax"),  dataIndex: 'maxscaledenom', flex:1, renderer: function(value, metadata) { if (value && value!="") return Math.round(value); else return "";} },
							    { text: ToloI18n.getMsg("ToloWMSExplorerPanel.grid.scalamin"),  dataIndex: 'minscaledenom', flex:1, renderer: function(value, metadata) { if (value && value!="") return Math.round(value); else return "";} }
							    ]	/*,
							    
							dockedItems: [{
							    xtype: 'pagingtoolbar',
						        store: ds,   // same store GridPanel is using
						        dock: 'bottom',
						        displayInfo: true
						    	}]*/
							});

		this.grid.getView().getSelectionModel().on('selectionchange', 
					function( selModel, selected, eOpts) {
											me.btnAddLayer.setDisabled(selected.length==0);
		});
							    										
							
		this.add(this.grid);
		
			
	}, 
	
	applicaFiltro: function(valore) {
		valore=valore.toUpperCase();
		var filter = new Ext.util.Filter({
			    filterFn: function(item) {
			        return (item.get('name').toUpperCase().indexOf(valore)!=-1) ||
			        	   (item.get('abstract').toUpperCase().indexOf(valore)!=-1) || 
			        	   (item.get('title').toUpperCase().indexOf(valore)!=-1);
			    }
			});
		
		this.grid.store.clearFilter();
		this.grid.store.addFilter(filter);
		
	}
	
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Pannello contenente visualizzatore WebGL Cesium
 * 
 */
Ext.define('TolomeoExt.ToloCesiumPanelExt', {
	extend: 'Ext.panel.Panel',

	cesiumWidget: null,
	
	/**
	 * @cfg {JSONObject}
	 * Parametri principali tolomeo (contenuti in paramPreset ed arricchiti)
	 */
	paramsJS: null,
	
	/** 
	 * Property: TOLOMEOServer
	 * {String}
	 */
	TOLOMEOServer: null,
	
	/** 
	 * Property: TOLOMEOStaticRoot
	 * {String}
	 */
	TOLOMEOStaticRoot: null,
	
	/** 
	 * Property: TOLOMEOContext
	 * {String}
	 */
	TOLOMEOContext: null,

	
	/**
	 * @cfg {Number}
	 * Longitudine Ovest iniziale
	 */
	startExtentWest: null,
	
	/**
	 * @cfg {Number}
	 * Longitudine Est iniziale
	 */
	startExtentEast: null,
	
	/**
	 * @cfg {Number}
	 * Latitudine nord iniziale
	 */
	startExtentNorth: null,
	
	/**
	 * @cfg {Number}
	 * Latitudine sud iniziale
	 */
	startExtentSouth: null,
	
	/**
	 * @cfg {String}
	 * Url da utilizzare per il terrain provider
	 */
	terrainUrl: null,
	
	/**
	 * @cfg {String}
	 * Credits da utilizzare per il terrain provider
	 */
	terrainCredits: null,
		

    initComponent: function(){
		
		//TODO FILTRARE OVUNQUE LAYERAGGREG MAPSERVER CGI
		
		TolomeoExt.Vars.ApplyIfDefaults(this);	
		
		this.terrainUrl = this.terrainUrl || this.paramsJS.layOut.visualizzazione3D.terrainUrl ; //'http://cesium.agi.com:80/smallterrain';
		this.terrainCredits = this.terrainCredits || this.paramsJS.layOut.visualizzazione3D.terrainCredits; //'Terrain data courtesy Analytical Graphics, Inc.';
		
		this.layout='fit';
		
		this.addEvents(
			/**
			 * @event onBeforePreInit
			 * Lanciato in fase di inizializzazione prima che al viewer cesium siano aggiunti i layer 
			 */
			'onBeforePreInit',
			
			/**
			 * @event onBeforePreInit
			 * Lanciato in fase di inizializzazione dopo che al viewer cesium sono stati aggiunti tutti i layer 
			 */
			'onAfterPreInit'
		);
		
        this.callParent(arguments);
	
        //this._creaCesiumWidget
        this.on('afterrender', function () { 
        							this.show3D( this.startExtentWest, this.startExtentNorth, this.startExtentEast, this.startExtentSouth ); 
        					}, 
        		this, {single:true});
     	//this.on('afterrender', this.pluginPreInit, this, {single:true});
        this.on('resize', this._resizeCesiumWidget);
                
	},
	
	/** 
	 * Esegue l'inizializzazione.
	 */
	pluginPreInit: function() {
		this.fireEvent("onBeforePreInit");				
	    this.addAllLayers();
		this.fireEvent("onAfterPreInit");
	},
	
	/**
	 * Rimuove tutti i layer.
	 */
	removeAllLayers: function() {
		 this.cesiumWidget.scene.imageryLayers.removeAll();
	},
	
	/** 
	 * Aggiunge tutti i layer
	 */
	addAllLayers: function() {
		var nMappa = 0;
		
		for (var i=0; i< this.paramsJS.mapDefinitions[nMappa].getLayerAggregationCount() ; i++) {
			this.refreshMap(i);
		}		
	},
	
	show3D: function(west, north, east, south) {
		if (this.cesiumWidget == null) {
			this._creaCesiumWidget();
		} else {
			this.removeAllLayers();		
		}
		this.gotoExtent(west, north, east, south);
		this.addAllLayers();
	}, 
	
	/**
	 * Aggiunge o modifica un layer WMS
	 * @param {Cesium.ImageryLayer} newCesiumLayer
	 * @param {Cesium.ImageryLayer} actualLayer
	 * @param {Number} position posizione in cui inserire il layer
	 */
	addOrChangeWMS: function(newCesiumLayer, actualLayer, position) {
		var layers = this.cesiumWidget.scene.imageryLayers;
		  if (actualLayer!=null) layers.remove(actualLayer);
		  if (position!==undefined && position!=null) {
			  layers.add(newCesiumLayer, position);
		  } else {
			  layers.add(newCesiumLayer);
		  }
	},
	
	/**
	 * Ricarica un layer
	 * @param {Number} numero identificativo dell'aggregazione layer da aggiornare
	 */
	refreshMap: function (nLayerAggreg) {
		
		var actualLayer = this.getLayerFromNAggreg(nLayerAggreg);
		var cl = this._creaCesiumLayer(nLayerAggreg);
		var position = this.getCesiumRequestedPosition(nLayerAggreg);
		
		if (cl!=null) {
			
			this.addOrChangeWMS(cl, actualLayer, position);
			
		} else {
			if (actualLayer) {
				if (position==1) {
					// se si sta per cancellare il baseLayer prima si porta un altro layer come base
					var layers = this.cesiumWidget.scene.imageryLayers;
					if (layers.length>1) {
						layers.lowerToBottom(layers.get(1));
					}
				}
				this.cesiumWidget.scene.imageryLayers.remove(actualLayer);
			}
		}
		
	},
	
	/**
	 * Restituisce il layer cesium che corrisponde ad una certa aggregazione
	 * @param {Number} nLayerAggreg numero di aggregazione del layer da recuperare
	 * @return {Cesium.ImageryLayer} il layer
	 */
	getLayerFromNAggreg: function(nLayerAggreg) {
		if (this.cesiumWidget==null) return null;
		var layers = this.cesiumWidget.scene.imageryLayers;
		for (var i=0; i<layers.length; i++) {
			var l = layers.get(i);
			if (l.nLayerAggreg==nLayerAggreg) return l;
		}
		return null;
	},
	
	/**
	 * Restituisce la posizione del layer cesium che corrisponde ad una certa aggregazione
	 * @param {Number} nLayerAggreg numero di aggregazione del layer da recuperare
	 * @return {Number} Posizione del layer
	*/
	getCesiumRequestedPosition: function(nLayerAggreg) {
		if (this.cesiumWidget==null) return null;
		var retVal=0;
		var layers = this.cesiumWidget.scene.imageryLayers;
		
		for (var i=0; i<layers.length; i++) {
			var l = layers.get(i);
			if (l.nLayerAggreg>nLayerAggreg) return i;
		}
		return null;
	},
	
	/**
	 * @private
	 */
	_resizeCesiumWidget: function() {
		if (this.cesiumWidget!=null) {
			this.cesiumWidget.resize(); 
		}
	},
	
	/**
	 * @private
	 */
	_creaCesiumWidget: function() {
		if (this.cesiumWidget==null){
			this.cesiumWidget = new Cesium.Viewer(this.body.id, {
													baseLayerPicker: false,
													geocoder: false,
													animation: false,
													homeButton: true,
													fullscreenButton: false,
													//fullscreenElement: this.body.id,
													sceneModePicker: false,
													timeline: false,
													imageryProvider: false } ); //new Cesium.CesiumWidget(this.body.id, { imageryProvider: false } );
			var cesiumTerrainProvider = new Cesium.CesiumTerrainProvider({
		    	url : this.terrainUrl,
		//    	proxy : new Cesium.DefaultProxy('http://localhost:8080/tolomeobinj/TolomeoProxyServlet'),
		    	credit : this.terrainCredits
			});
			
			this.cesiumWidget.scene.terrainProvider = cesiumTerrainProvider;
			this.gotoExtent(this.startExtentWest, this.startExtentNorth, this.startExtentEast, this.startExtentSouth);
			
			//this.cesiumWidget.fullscreenElement = this.body.id;
			
			var me = this;
			
			this.cesiumWidget.homeButton.viewModel.command.beforeExecute.addEventListener(function(commandInfo){
				me.gotoExtent(me.startExtentWest, me.startExtentNorth, me.startExtentEast, me.startExtentSouth);
				//Tell the home button not to do anything.
				commandInfo.cancel = true;
			});
			
		}
	},

	/**
	 * @private
	 */
	_creaCesiumLayer: function(nLayerAggreg){
		var nMappa=0;
		var sep = ',';
		var layerAggr = this.paramsJS.mapDefinitions[nMappa].getLayerAggregation(nLayerAggreg);
		var server = layerAggr.server;
		var layAndStyle = this.paramsJS.getLayerAggregLayersAndStylesStrings(nMappa, nLayerAggreg, sep, null); 
		
		if (layAndStyle.layers=="") {
			return null;
		}
		
		var laysep = layAndStyle.layers;
		if (sep!=',') {
			// sostituisce il separatore con quello giusto per WMS
			var pattern = new RegExp(sep,'g');
			laysep = laysep.replace(pattern, ',');
		} 
		
		var stilisep = layAndStyle.stili;
		if (sep!=',') {
			// sostituisce il separatore con quello giusto per WMS
			var pattern = new RegExp(sep,'g');
			stilisep = stilisep.replace(pattern, ',');
		}

		var currProxy = undefined;
		if (this.paramsJS.layOut.visualizzazione3D && server.usaProxyPer3D) {
			var pr = (server.proxyPer3dUrl && server.proxyPer3dUrl!="") ? server.proxyPer3dUrl : this.TOLOMEOServer + this.TOLOMEOContext + "/TolomeoProxyServlet"
			currProxy = new Cesium.DefaultProxy(pr)
		} 
		
		var attr = "";
		if (layAndStyle.attribution) {
			if (layAndStyle.attribution.constructor === Array) {
				if (layAndStyle.attribution.length>0) {
					var sep = "";
					for (var i = 0; i<layAndStyle.attribution.length>0; i++) {
						if (typeof layAndStyle.attribution[i] === 'string') {
							attr += sep + layAndStyle.attribution[i];
						} else {
							attr += sep + layAndStyle.attribution[i].title;
						}
						sep = ","
					}
				} else {
					attr = "";
				}
				
			} else {
				if (typeof layAndStyle.attribution === 'string') {
					attr += layAndStyle.attribution;
				} else {
					attr += layAndStyle.attribution.title;
				}
			}		
		}
		
		var wms = {
				url: server.url,
				layers : laysep,
				credit: attr,
				parameters: { 	styles: stilisep, 
						transparent : 'true',
        				format : 'image/png'
        		},
				//credit: server.id,
				proxy : currProxy
		};
		
		var layers = this.cesiumWidget.scene.imageryLayers;
		var provider = new Cesium.WebMapServiceImageryProvider(wms);
		var lay = new Cesium.ImageryLayer(provider, {
									alpha: layerAggr.opacity
								});
		lay.nLayerAggreg = nLayerAggreg;
		
		return lay;
	}, 
	
	gotoExtent: function(west, north, east, south) {
	
		if (west!=null && east!=null && north!=null && south!=null) {
			var westRad = Cesium.Math.toRadians(west);
		  	var southRad = Cesium.Math.toRadians(south);
		  	var eastRad = Cesium.Math.toRadians(east);
		  	var northRad = Cesium.Math.toRadians(north);

		  	var extent = new Cesium.Rectangle(westRad, southRad, eastRad, northRad);  
			
		    var scene = this.cesiumWidget.scene;
		    var ellipsoid = Cesium.Ellipsoid.WGS84;

		    scene.camera.viewRectangle(extent, ellipsoid);	
		}
	}

});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.define('TolomeoExt.ToloCommand', {

	//extend: 'Ext.util.Observable',

	statics: {
		//CMDZOOMTO: function() { return	1; },
		//CMDTOCUNCHECKALL: function() { return	2; },
		//CMDTOCCHECK: function() { return	3; },
		//cmdMapping: [
		//				'',
		//				'zoomTo',
		//				'tocCheck'
		//			],
		createCommand: function(commandCode, args) {
			return Ext.createByAlias(
				//cmdMapping['tolocommand.' + commandCode],
				'tolocommand.' + commandCode,
				args
			);
		}
	},
	
/*	config: {
		//commandCode: null,	
		args: null
	},
*/
	constructor: function(config) {

		this.initConfig(config);
		this.callParent(arguments);
	},
	
	run: function(api) {
		
	},
	
	encodeArgs: function() { },
	
	toJSON: function() {
		return "{\"c\":\"" + this.commandCode + "\",\"a\":" + this.encodeArgs() + "}";
	}

});

Ext.define('TolomeoExt.ToloCommand.tocCheck', {

	extend: 'TolomeoExt.ToloCommand',
	alias: ['tolocommand.tocCheck'],
	
	commandCode: 'tocCheck',
	
	config: {
		
		/**
		 * 
		 * @cfg {String[]} 
		 */
		pool: null,
		
		entry: null,
		
		/**
		 * @cfg {String[]} contiene elenco delle descrizioni delle voci di tipo text da attivare
		 */
		tentry: null,
		
		/**
		 * 
		 * @cfg {String} mode Valori possibili <br/>
		 * - listedOnly: modifica solo le voci di legenda listate
		 * - uncheckOthers: deseleziona le voci di legenda non listate
		 * - checkOthers: seleziona le voci di legenda non listate
		 */
		mode: 'listedOnly',
		
		/**
		 * @cfg {Number} ver versione tracciato. 
		 * - Non presente: versione originaria
		 * - 2: aggiunta trasparenza layer
		 */
		ver: null
	},
	
	constructor: function(config) {

		this.initConfig(config);
		this.callParent(arguments);
	},
	
	run: function(api) {
		
		
		api.TOCPanel.on('tocGuiCreate',
			function() {
				if (this.mode=='listedOnly') {
					// loop sulle voci listate
					for (var i=0; i<this.getTocEntryCount(); i++) {
						var tocEntry = this.getTocEntry(i);
						var serverID = this.pool[tocEntry.s]; //"RTCASTORE";
						var name = tocEntry.l; //"r_toscan_cst_fogli";
						var state = (this.mode=='listedOnly') ? tocEntry.a : (this.mode=='uncheckOthers');
						var lay = api.TOCPanel.tocInfo.searchLayerInfo(serverID, name);
						if (lay!=null  && lay.hidden==false && lay.itemType=='layer') {
							if (lay.state) {
								api.TOCPanel.checkAllParentCat(lay.catTreeIdx, true);
								// Se la legenda lo consente apre tutte le categorie fino al layer acceso 
								if (api.TOCPanel.expandCategories) {
									api.TOCPanel.expandCategories(lay.catTreeIdx);
								}
							}
							if (lay.checked!=state) api.TOCPanel.setLayerStateChange(lay.catTreeIdx, lay.layTreeIdx, state );
						}
					}
				} else {
					// Inizializzo stateBuff con il valore di default in funzione di mode
					// Solo per i layer non hidden
					api.TOCPanel.tocInfo.onEachLayer(
						function(cat, lay, catIdx, layIdx) {
								if (lay.hidden==false) lay.stateBuff = (this.mode=='checkOthers');
						},
						this
					);
					// modifico stateBuff e opacityBuff con il valore imposto da tocEntryList (solo per layer non hidden)
					for (var i=0; i<this.getTocEntryCount(); i++) {
						var tocEntry = this.getTocEntry(i);
						var serverID = this.pool[tocEntry.s]; //"RTCASTORE";
						var name = tocEntry.l; //"r_toscan_cst_fogli";
						var state = (this.mode=='listedOnly') ? tocEntry.a : (this.mode=='uncheckOthers');
						var opacityBuff = (this.ver && this.ver>=2) ? tocEntry.o : undefined;
						var styleBuff = (this.ver && this.ver>=3) ? tocEntry.style : undefined;
						var lay = api.TOCPanel.tocInfo.searchLayerInfo(serverID, name);
						if (lay!=null && lay.hidden==false) {
							lay.stateBuff=state;
							lay.opacityBuff = opacityBuff;
							lay.styleBuff = styleBuff; 
						}
					}
					
					// modifico statebuff con il valore imposto solo per le voci di tipo text
					if (this.tentry!=null) {
						for (var i=0; i<this.tentry.length; i++) {
							var tocTextEntry = this.tentry[i];
							var lay = api.TOCPanel.tocInfo.searchLayerInfoByDesc(tocTextEntry, 'text');
							if (lay!=null && lay.hidden==false) {
								lay.stateBuff=true;
							}
						}	
					}
					
					// modifico tutti gli stati che devono cambiare
					api.TOCPanel.tocInfo.onEachLayer(
						function(cat, lay, catIdx, layIdx) {
							if (lay.hidden==false && lay.itemType=='layer' ) {
								// Questo deve farlo comunque, perchè potrebbe avere gli antenati spenti pur essendo già acceso
								if (lay.stateBuff) { 
									api.TOCPanel.checkAllParentCat(lay.catTreeIdx, true);
									// Se la legenda lo consente apre tutte le categorie fino al layer acceso 
									if (api.TOCPanel.expandCategories) {
										api.TOCPanel.expandCategories(lay.catTreeIdx);
									}
								}
								// Questo lo deve fare solo se lo stato è diverso da quello voluto (altrimenti è inutile)
								if (lay.checked!=lay.stateBuff) {
									api.TOCPanel.setLayerStateChange(catIdx, layIdx, lay.stateBuff );
								}
								if (lay.opacityBuff!==undefined && lay.opacity!=lay.opacityBuff) {
									api.TOCPanel.layerOpacityChange(catIdx, layIdx, lay.opacityBuff*100 );
								}
								if (lay.styleBuff!==undefined){
									if(lay.styleCapable && lay.style!=lay.styleBuff && lay.definedStyles) {
										for(var i in lay.definedStyles){
											if(lay.definedStyles[i].name == lay.styleBuff){
												api.TOCPanel.setLayerStyle(catIdx, layIdx, lay.styleBuff );
												break;
											}
										}
										
									}
								}
								
							} else {
								if (lay.hidden==false && lay.itemType == 'text') {
									if (lay.stateBuff) { 
										api.TOCPanel.checkAllParentCat(lay.catTreeIdx, true);
										// Se la legenda lo consente apre tutte le categorie fino al layer acceso 
										if (api.TOCPanel.expandCategories) {
											api.TOCPanel.expandCategories(lay.catTreeIdx);
										}
									}	
								}
							}
						},
						this
					);
				}
			},
			this);			
			return true;
	},
	
	getTocEntry: function(index) {
		var basePos = index * this.getRecordLength();
		var retVal = { s: this.entry[basePos], l: this.entry[basePos+1], a: (this.mode=='listedOnly') ? this.entry[basePos+2] : undefined };
		if (this.ver && this.ver>=2) {
			if (this.mode=='listedOnly') retVal.o = this.entry[basePos+3];
			else retVal.o = this.entry[basePos+2];
		}
		
		if (this.ver && this.ver>=3) {
			if (this.mode=='listedOnly') retVal.style = this.entry[basePos+4];
			else retVal.style = this.entry[basePos+3];
		}
		
		return retVal; 
	},
	
	getTocEntryCount: function() {
		return Math.floor(this.entry.length / this.getRecordLength());
	},
	
	getRecordLength: function() {
		var extraFields = (this.ver && this.ver==2) ? 1 : 0;
		return (this.mode=='listedOnly') ? 3 + extraFields  : 2 + extraFields;
	},
	
	addTocEntry: function(serverID, layerName, state, opacity, style) {
		this.entry = this.entry || [];
		this.pool = this.pool || [];
		
		var serverIndex = this.pool.indexOf(serverID);
		
		if (serverIndex==-1) {
			serverIndex = this.pool.push(serverID) - 1;
		}
		
		this.entry.push(serverIndex, layerName);
		if (this.mode=='listedOnly') {
			this.entry.push(state);	
		}
		
		if ((this.ver && this.ver>=2)) {
			this.entry.push(opacity);
		}
		
		if (this.ver && this.ver>=3) {			
			this.entry.push(style ? style : "");			
		}
		
	},
	
	addTocTextEntry: function(descrizione) {
		this.tentry = this.tentry || [];
		this.tentry.push(descrizione);
	},
	
	encodeArgs: function() {
		
		var obj = { mode: this.mode, entry: this.entry, tentry: this.tentry, pool: this.pool, ver: this.ver };
		
		return Ext.JSON.encode(obj);
	}

});

Ext.define('TolomeoExt.ToloCommand.zoomTo', {

	extend: 'TolomeoExt.ToloCommand',
	alias: ['tolocommand.zoomTo'],
	
	commandCode: 'zoomTo',
	
	config: {
		/**
		 * @cfg {Number} Longitudine
		 */
		x: null,	
	
		/**
		* @cfg {Number} Latitudine
		*/
		y: null,
		
		/**
	 	* @cfg {Number} Scala
		*/
		s: null
	},
	
	constructor: function(config) {

		this.initConfig(config);
		this.callParent(arguments);
	},
	
	run: function(api) {
		
		api.viewer.on('onAfterPostInit',
			function() {
				api.viewer.pluginGotoPosition(this.x, this.y, this.s);		
			}, this,
			{single:true}
		);
		
		//api.viewer.pluginGotoPosition(this.x, this.y, this.s);
		return true;
	},
	
	encodeArgs: function() {
		var obj = { x: this.x, y: this.y, s: this.s};
		
		return Ext.JSON.encode(obj);
	}
	

});

Ext.define('TolomeoExt.ToloCommand.zoomToExtent', {

	extend: 'TolomeoExt.ToloCommand',
	alias: ['tolocommand.zoomToExtent'],
	
	commandCode: 'zoomToExtent',
	
	config: {
		/**
		 * 
		 * @type {Number} 
		 */
		left: null,
		
		/**
		 * 
		 * @type {Number} 
		 */
		bottom: null,
		
		/**
		 * 
		 * @type {Number} 
		 */
		right: null,
		
		/**
		 * 
		 * @type {Number} 
		 */
		top: null
		
	},
	
	constructor: function(config) {

		this.initConfig(config);
		this.callParent(arguments);
	},
	
	run: function(api) {
		
		api.viewer.on('onAfterPostInit',
			function() {
				var bbox = new BBox(this.left, this.bottom, this.right, this.top);
				this.zoomToExtent(bbox, 0);
			}, this,
			{single:true}
		);
		return true;
	},
	
	encodeArgs: function() {
		var obj = { left: this.left, bottom: this.bottom, right: this.right, left: this.left};
		
		return Ext.JSON.encode(obj);
	}
	

});


Ext.define('TolomeoExt.ToloCommand.addPopups', {

	extend: 'TolomeoExt.ToloCommand',
	alias: ['tolocommand.addPopup'],
	
	commandCode: 'addPopup',
	
	config: {
		
		/**
		 * 
		 * @type {Object[]} 
		 */
		conf: null
		
	},
	
	constructor: function(config) {

		this.initConfig(config);
		this.callParent(arguments);
	},
	
	run: function(api) {
		
		api.viewer.on('onAfterPostInit',
			function() {
				for (var i=0; i<this.conf.length; i++) {
					api.viewer.pluginAddPopup(this.conf[i].x, this.conf[i].y, this.conf[i].t, false, this.conf[i].e);	
				}		
			}, this,
			{single:true}
		);
		return true;
	},
	
	encodeArgs: function() {
		var obj = { conf: this.conf };
		
		return Ext.JSON.encode(obj);
	}

});


Ext.define('TolomeoExt.ToloCommand.identify', {

	extend: 'TolomeoExt.ToloCommand',
	alias: ['tolocommand.identify'],
	
	commandCode: 'identify',
	
	config: {
		/**
		 * 
		 * @type {Number} 
		 */
		x: null,
		
		/**
		 * 
		 * @type {Number} 
		 */
		y: null,
		
		/**
		 * 
		 * @type {String} 
		 */
		srid: null,
		
		/**
		 * 
		 * @type {String} 
		 */
		layerName: null
		
	},
	
	constructor: function(config) {

		this.initConfig(config);
		this.callParent(arguments);
	},
	
	run: function(api) {
		
		api.TOCPanel.on('tocGuiCreate',
			function() {			
				var point = api.reprojectToCurrentCrs(new Point(this.x,this.y),this.srid);
				var lonlat = {lon:point.x,lat:point.y};
				var pixel = api.viewer.pluginGetPixelFromCoordinate(lonlat);
				var lay = null;
				
				if(this.layerName){
					var lay = api.TOCPanel.tocInfo.searchLayerInfo(null,this.layerName);
				}
				
				api.onMappaSelect(new Point(lonlat.lon, lonlat.lat),'firstOnTop',false,true, pixel.x,pixel.y,(lay?lay.codTPN:lay));								
			}, this,
			{single:true}
		);
		
		return true;
	},
	
	encodeArgs: function() {
		var obj = { left: this.left, bottom: this.bottom, right: this.right, left: this.left};
		
		return Ext.JSON.encode(obj);
	}
	

});

Ext.define('TolomeoExt.ToloCommand.startPopup', {

	extend: 'TolomeoExt.ToloCommand',
	alias: ['tolocommand.startPopup'],
	
	commandCode: 'startPopup',
	
	config: {
		
		/**
		 * 
		 * @type {String} 
		 */
		msg: null
		
	},
	
	constructor: function(config) {

		this.initConfig(config);
		this.callParent(arguments);
	},
	
	run: function(api) {		
		
		Ext.create('Ext.window.Window', {
		    title: 'Avviso',
		    iconCls: 'iconPermalink',
		    modal: true,
		    height: 200,
		    width: 400,
		    layout: 'fit',
		    items: [{
					  xtype: 'box',
					  autoScroll: true,
					  autoEl: {
					     tag: 'div',
					     html: this.msg
					    }}
		            ],
		    buttons: [
			          { text: 'OK',
			        	listeners: {
			        		click: function() {
			        			this.up('.window').close(); 
				        	}
				         }
			          }
			    ]}).show();
		
		return true;
	},
	
	encodeArgs: function() {
		var obj = { msg: this.msg };
		
		return Ext.JSON.encode(obj);
	}

});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.define('TolomeoExt.ToloProcedure', {

	extend: 'Ext.util.Observable',

	commands: null,
	
	config: {
		cmdUrl: null, 
		commands: null
	},

	constructor: function(config) {
		this.initConfig(config);
		this.callParent(arguments);
		
		this.commands=this.commands||[];
		
		if (config.cmdUrlComp) {
			var decomp = LZString.decompressFromBase64(config.cmdUrlComp);
			this._parseUrl(decomp);
		}
		
		if (config.cmdUrl) {
			this._parseUrl(config.cmdUrl);		
		}
		
		
	},
	
	/**
	 * @private
	 * @param {String} cmdUrl Formato
	 * 		{ c: [	// Array di comandi
	 * 				{ c: 0    			// command code
	 * 				  a: [ { }, { } ]	// args
	 * 				},
	 * 				{ c: ...} 
	 * 				]
	 * 		}
	 */
	_parseUrl: function(cmdUrl) {
		var arg = Ext.JSON.decode(cmdUrl, true);
		
		if (arg) {
			var cmdConfigArr = arg.c;	// Array di comandi
			
			for (var i = 0; i < cmdConfigArr.length; i++) {
				var cConfig = cmdConfigArr[i];
		
				var c = TolomeoExt.ToloCommand.createCommand(cConfig.c, cConfig.a);
				/*
				var c = Ext.create('TolomeoExt.ToloCommand', {
							commandCode: cConfig.c,
							args: cConfig.a
					});
					*/
				this.commands.push(c);
				
			}
		} else {
			//TODO Errore nella stringa
			
		}
	},
	
	addCommand: function(cmd) {
		this.commands.push(cmd);
	},
	
	getCommandCount: function(){
		return this.commands.length;
	},

	getCommand: function(nLine) {
		return this.commands[nLine];
	},

	run: function(api) {
		var bOnOpenDrawMap=false;
		var buff;
		
		for (var i = 0; i < this.getCommandCount(); i++) {
			buff = this.getCommand(i).run(api);
			bOnOpenDrawMap = bOnOpenDrawMap || buff;
			//this.runLine(api, i);
		}
		return bOnOpenDrawMap;
	},

	/*
	runLine: function(api, nLine) {
		var cmd = this.getCommand(nLine);
		var args = cmd.getArgs();

		switch (cmd.getCommandCode()) {
		case TolomeoExt.ToloCommand.CMDZOOMTO:
					//api.viewer.pluginToolSelectZoomAll();
					//api.viewer.bOnOpenDrawMap=true;
		
					api.viewer.pluginGotoPosition(args[0].x, args[0].y, args[0].s);
					
					//api.zoomToScale(1000);
					//api.TOCPanel.on('tocGuiCreate',
					//	function() {
					//		api.zoomToScale(1000); 
					//	});	
					break;
		case TolomeoExt.ToloCommand.CMDTOCUNCHECKALL: 
					api.viewer.bOnOpenDrawMap=true;
					api.TOCPanel.on('tocGuiCreate',
						function() {
							api.TOCPanel.setCategoryStateChange(0,false);
							//api.TOCPanel.setLayerStateChange(0, 0, true); 
						});	
					break;
		case TolomeoExt.ToloCommand.CMDTOCCHECK:
					api.viewer.bOnOpenDrawMap=true;
					api.TOCPanel.on('tocGuiCreate',
						function() {
							var serverID = args[0].s; //"RTCASTORE";
							var name = args[0].l; //"r_toscan_cst_fogli";
							var state = args[0].a;
							var lay = api.TOCPanel.tocInfo.searchLayerInfo(serverID, name);
							if (lay!=null) {
								api.TOCPanel.setLayerStateChange(lay.catTreeIdx, lay.layTreeIdx, state );
							}
							//api.viewer.pluginToolSelectZoomAll();
							//api.viewer.pluginRefreshMap();
						});				
					break;
			default:
		
				break;
		}
		
	},*/ 
	
	toJSON: function() {
		return "{\"c\":" + Ext.JSON.encode(this.commands) + "}";
	}
		
});
	/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Plugin per il display di feature vettoriali 
 * in una griglia ExtJs.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.ToloFeatureGridPanel', {

	extend: 'Ext.Panel',

	alias: "widget.tolomeo_featurecomponent",
	
	id: "tolomeo_featuregrid",

	/**
	 * @property {Object} paramsJS
	 * Configurazioni specifiche del file di preset.
	 */
	paramsJS: null,

	/**
	 * @cfg {String} TOLOMEOServer
	 * URL di base del contesto di Tolomeo.
	 */
	TOLOMEOServer: null,

	/**
	 * @cfg {String} TOLOMEOContext
	 * Contesto di Tolomeo.
	 */
	TOLOMEOContext: null,

	/**
	 * @property {Object} schema
	 * Schema nome e tipo degli attributi usati per la configurazione delle griglia
	 */
	schema: null,

	/**
	 * @cfg {TolomeoExt.ToloFeatureManager} qbFeatureManager (required)
	 * Gestore di richieste e operazioni che coinvolgono le features.
	 */
	qbFeatureManager: null,

	/**
	 * @property {TolomeoExt.events.ToloQueryBuilderEvtManager} qbEventManager
	 * Gestore di eventi per il query builder.
	 */
	qbEventManager: null,
		
    /**
	 * @property {OpenLayers.Layer.Vector} featureLayer 
	 * Layer vettoriale contenente le features corrispondenti alla ricerca.
	 */
	featureLayer: null,
	
	/**
	 * @property {OpenLayers.Layer.Vector} highlightLayer 
	 * Layer vettoriale mostrante le singole feature corrispondenti alla ricerca.
	 */
	highlightLayer: null,
	
	highlightFeatureStyle: {		
		fillColor: "#ffff00",		
		fillOpacity: 0.4,
		strokeColor: "#ffff00",
		strokeOpacity: 0.4
	},
	
	layout: 'fit',
	
	/**
     * Inizializza un oggeto di tipo TolomeoExt.ToloFeatureGridPanel.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	initComponent: function(config) {		
		
		var me = this;
		
		if(!this.featureLayer){
			this.featureLayer = new OpenLayers.Layer.Vector("gridFeatureLayer", {
				displayInLayerSwitcher: false
			});
		}
		
		if(!this.highlightLayer){
			this.highlightLayer = new OpenLayers.Layer.Vector("gridHighlightLayer", {
				displayInLayerSwitcher: false
			});
		}
		
		if(!this.qbEventManager){
			this.qbEventManager = Ext.create('TolomeoExt.events.ToloQueryBuilderEvtManager');
		}
		
		this.qbFeatureManager.setProxy();
		this.qbFeatureManager.setFeatureStore(Ext.create('Ext.data.JsonStore', {
			fields: [],
			pageSize: this.qbFeatureManager.maxFeatures,
			proxy: this.qbFeatureManager.getProxy()
		}));
		
		var exportMenu = Ext.create('Ext.button.Split', {
            tooltip: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.tooltip"),
            iconCls: "pageexport",
            menu : {
                items: [{
                    text: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.SHP.text"),
                    menu: {
                        showSeparator: false,
                        items: [{
							text: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.SHP.tuttepag.text"),
							handler: function(){
								this.qbFeatureManager.fireEvent("export", {format: "shp", items: "all"});
							}, 
							scope: this
						}, {
							text: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.SHP.pagcorrente.text"),
							handler: function(){
								this.qbFeatureManager.fireEvent("export", {format: "shp", items: "single"});
							}, 
							scope: this
						}]
                    }
                }, {
                    text: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.Spatialite.text"),
                    name: "spatialiteExporter",
                    menu: {
                      showSeparator: false,
                      items: [{
							text: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.Spatialite.tuttepag.text"),							
							handler: function(){
								this.qbFeatureManager.fireEvent("export", {format: "spatialite", items: "all"});
							}, 
							scope: this
					   }, {
							text: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.Spatialite.pagcorrente.text"),
							handler: function(){
								this.qbFeatureManager.fireEvent("export", {format: "spatialite", items: "single"});
							}, 
							scope: this
					   }]
                    }
                }, {
                    text: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.CSV.text"),
                    menu: {
                      showSeparator: false,
                      items: [{
							text:  ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.CSV.tuttepag.text"),
							handler: function(){
								this.qbFeatureManager.fireEvent("export", {format: "csv", items: "all"});
							}, 
							scope: this
					   }, {
							text: ToloI18n.getMsg("ToloFeatureGridPanel.exportMenu.CSV.pagcorrente.text"),
							handler: function(){
								this.qbFeatureManager.fireEvent("export", {format: "csv", items: "single"});
							}, 
							scope: this
					   }]
                    }
                }]
            }
		});
        
		config = Ext.apply({
			xtype: "tolomeo_featuregrid",
			autoScroll: true,
			header: {
				hidden: true
			},
			//height: 250,			
			border: false,
			title: this.title,
			store: this.qbFeatureManager.featureStore,
			colums: [],
		    dockedItems: [{
		        xtype: 'pagingtoolbar',
		        store: this.qbFeatureManager.featureStore,   // same store GridPanel is using
		        dock: 'bottom',
		        displayInfo: true,
		        disabled: true,
		        items: [
					{
						tooltip:  ToloI18n.getMsg("ToloFeatureGridPanel.btnVisSuMappa.tooltip"),
						name: "viewOnMapButton",
						enableToggle: true,
						iconCls: "pageviewonmap",
						handler: function(button){
							this.updateLayerOnMap(this.qbFeatureManager.featureStore, button.pressed);
						},
						scope: this
					},
					{
						tooltip:  ToloI18n.getMsg("ToloFeatureGridPanel.btnZoomPag.tooltip"),
						name: "zoomOnPageButton",
					    iconCls: "pagezoomonmap",
						handler: function(){
							this.qbEventManager.fireEvent("zoomtomapextent", {dataExtent: this.pageBBOx});
						}, 
						scope: this
					}, "-", exportMenu
		        ]
		    }],
		    listeners:{
		    	scope: this,
		    	zoomtofeatureextent: function(evt){
		    		this.qbEventManager.fireEvent("zoomtomapextent", evt);
		    	},
		    	itemmouseenter: function(scope,record){
		    		me.highlightItemGeometry(record);
		    	},
		    	itemmouseleave: function(scope,record){
		    		me.dehighlightItemGeometry(record);
		    	}
		    }
		}, config || {});

		this.items = [config];
		this.callParent();
		
		this.on("afterrender", function(){
			this.waitMask = new Ext.LoadMask(this.id, {msg: ToloI18n.getMsg("ToloFeatureGridPanel.btnZoomPag.tooltip")});
		}, this);

		// /////////////////////////////////////
		// FeatureManager events's listeners
		// /////////////////////////////////////
		this.qbFeatureManager.on({
			scope: this,
			layerchange: function(results){				
				//	this.ownerCt.expand();								
				var featureGrid = this.query("tolomeo_featuregrid")[0];
				featureGrid.setStore(featureGrid.store, results);
			},
			loadfeatures: function(results, store){
				this.waitMask.hide();
				this.ownerCt.expand();
			},
			loadfeaturesfailure: function(){
				this.waitMask.hide();
			},
			resetfeaturelayer: function(){
				this.updateLayerOnMap(null, false);
				
				//
        		// Disable the paging toolbar
        		//
        		this.query("pagingtoolbar")[0].disable();
        		
        		// Collapse the Grid
//        		this.ownerCt.collapse();
			}
		});
		
    	this.qbFeatureManager.featureStore.on("beforeload", function(store, operation, eOpts){
    		if(operation){
    			//this.qbFeatureManager.maxFeatures = operation.limit;
    			//this.qbFeatureManager.startIndex = operation.start;
    		}
    	}, this);
    	
    	
    	this.qbFeatureManager.on("beforeloadfeatures", function(codTPN){this.queriedCodTPN = codTPN;},this);
    	
    	this.qbFeatureManager.featureStore.on("load", function(store, records, successful, eOpts){
    		if (successful) {
	    		if(records && records.length > 0){
	        		var proxy = store.getProxy();
	        		var reader = proxy.getReader();
	        		var metadata = reader.metaData;
	        		
	        		this.pageBBOx = OpenLayers.Geometry.fromWKT(metadata.pageBBOX).getBounds();
	        		
	        		//
	        		// Enable the paging toolbar
	        		//
	        		this.query("pagingtoolbar")[0].enable();
	        		
	        		//
	        		// Check if the vector layers on map should be updated
	        		//
	        		var button = this.query("[name=viewOnMapButton]")[0];
	        		if(button.pressed){
	        			this.updateLayerOnMap(store, button.pressed);
	        		}
	        		
	        		this.query("[name=spatialiteExporter]")[0].setDisabled(!this.paramsJS.withSpatialiteExporter(this.queriedCodTPN));
	        		
	    		}else{
	                Ext.Msg.show({
	                    title: ToloI18n.getMsg("ToloFeatureGridPanel.infoRisultato.title"),
	                    msg: ToloI18n.getMsg("ToloFeatureGridPanel.msgNessuno"),
	                    buttons: Ext.Msg.OK,
	                    icon: Ext.MessageBox.INFO
	                });
	    		}
    		} else {
    		    Ext.Msg.show({
    		    	title: ToloI18n.getMsg("ToloFeatureGridPanel.infoRisultato.title"),
                    msg: store.proxy.reader.rawData.msgErrore,
                    buttons: Ext.Msg.OK,
                    icon: Ext.MessageBox.INFO
                });
    		}
    	}, this);
	},
	
	/**
     * Aggiorna il layer vettoriale sulla mappa aggiornando le features in esso contenute.
     * @param {Ext.Data.Store} store Un oggetto che rappresenta lo store della griglia. 
	 * @param {Boolean} pressed Indica se il relativo pulsante nella paging toolbar è premuto.
     */
	updateLayerOnMap: function(store, pressed){
		if(pressed){
			var store = this.qbFeatureManager.featureStore;
			var count = store.getCount(); // the elements inside the current page
			var records = store.getRange(0, count-1);
			
			// Create the OL features vector
			var features = [];
			for(var i=0; i<records.length; i++){
				var record = records[i];
				
				var attributes = {};
				for(key in record.data){
					if(key != "geometry"){
						attributes[key] = record.data[key];
					}
				}
				
				var geometry = OpenLayers.Geometry.fromWKT(record.data.geometry);
				var feature = new OpenLayers.Feature.Vector(geometry, attributes, null);
				features.push(feature);						
			}
			
			this.featureLayer.removeAllFeatures();
			this.featureLayer.addFeatures(features);
			this.qbEventManager.fireEvent("addlayer", this.featureLayer);
		}else{
			this.qbEventManager.fireEvent("removelayer", this.featureLayer);
		}
	},
	
	/**
	 * Metodo che fa l'highlight della geometria relativa alla riga 
	 * @param {} record
	 */
	highlightItemGeometry: function(record){		
		var geometry = OpenLayers.Geometry.fromWKT(record.data.geometry);
		var feature = new OpenLayers.Feature.Vector(geometry, {}, this.highlightFeatureStyle);
		this.highlightLayer.addFeatures(feature);
		this.qbEventManager.fireEvent("addlayer", this.highlightLayer);
	},
	
	/**
	 * Metodo che fa l'dehighlight della geometria relativa alla riga 
	 * @param {} record
	 */
	dehighlightItemGeometry: function(){		
		this.highlightLayer.removeAllFeatures();
		this.qbEventManager.fireEvent("removelayer", this.highlightLayer);
	}

});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Plugin per la gestione di richieste e operazioni 
 * che coinvolgono le features.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.ToloFeatureManager', {
	
	extend: 'Ext.util.Observable',
	
	id: "qb_featuremanager",
	
	/**
	 * @cfg {String} TOLOMEOServer
	 * URL di base del contesto di Tolomeo.
	 */
	TOLOMEOServer: null,
	
	/**
	 * @cfg {String} TOLOMEOContext
	 * Contesto di Tolomeo.
	 */
	TOLOMEOContext: null,

	/**
	 * @property {Ext.Data.Store} featureStore
	 * Store delle features ritornate dal server a seguito di una richiesta.
	 */
	featureStore: null,
	
	/**
	 * @cfg {Number} maxFeatures [maxFeatures="10"]
	 * Massimo numero di elementi per pagina.
	 */
	maxFeatures: 10,
			
	/**
	 * @cfg {Number} startIndex [startIndex="0"]
	 * Indice di pagina per richieste paginate.
	 */
	startIndex: 0,
	
	/**
	 * @property {Ext.Data.Proxy} proxy
	 * Proxy Ext per le richieste Ajax cross-domain.
	 */
	proxy: null,
	
	/**
     * Crea un nuovo TolomeoExt.ToloFeatureManager.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	constructor: function(config) {
		this.callParent(arguments);
		
		Ext.apply(this, config);
		
		this.addEvents(
	        /**
			 * @event
			 * Lanciato alla selezione di un nuovo layer dalla form.
			 */
			"layerchange",
			
	        /**
			 * @event
			 * Lanciato se il caricamento delle features fallisce.
			 */
			"loadfeaturesfailure",
			
	        /**
			 * @event
			 * Lanciato quando le features sono state caricate.
			 */
			"loadfeatures",
			
	        /**
			 * @event
			 * Lanciato prima di caricare le features da servizio remoto.
			 */
			"beforeloadfeatures",
			
	        /**
			 * @event
			 * Lanciato per reimpostare i parametri della richiesta.
			 */
			"resetquery",
			
	        /**
			 * @event
			 * Lanciato prima che avvenga la selezione di un nuovo layer dalla form del query builder.
			 */
			"beforelayerchange",
			
	        /**
			 * @event
			 * Lanciato al termine delle operazioni di export.
			 */
			"export",
			
	        /**
			 * @event
			 * Lanciato prima dell'avvio di una operazione di export.
			 */
			"beforedataexport"
		);	
		
		this.on("resetquery", this.resetQuery);
		this.on("export", this.exportPage);		
		this.on("layerchange", this.onLayerChange);
		this.paginationSupported = false;
		this.dummyMaxFeature = 1000000;
	},
	
	/**
     * Esporta i dati in griglia secondo i formati supportati (SHP, CSV, Spatialite).
     * @param {Object} options Oggetto contenente le opzioni per lo scaricamento dei dati. 
     *
     */
	exportPage: function(options){
        this.fireEvent("beforedataexport");
		
		var params = {
			format: 'ext',
			filter: this.proxy.extraParams.filter,
			codTPN: this.proxy.extraParams.codTPN,
			format: options.format,
			startIndex: options.items == "all" ? -1 :  this.startIndex,
			maxFeatures: (options.items == "all" || !this.paginationSupported) ? -1 :  this.maxFeatures,
			ogcFilterVersion: this.proxy.extraParams.ogcFilterVersion
		};
		
    	var submitOpt = {
    		url: this.TOLOMEOServer + this.TOLOMEOContext + '/SearchExportServlet',
    		method: 'POST',
    		params: params,
    		waitMsg: ToloI18n.getMsg("ToloFeatureManager.attesa"),
    		success: function(results, store){
    			var result = results[0];
    			if(result){
    				location.href = this.TOLOMEOServer + this.TOLOMEOContext + '/SearchExportServlet?filename=' + result.data.Descrizione;
    			}
    		},
    		failure: this.doAjaxFailure(),
    		scope: this
    	};
    	
		new TolomeoExt.ToloCrossAjax().request(submitOpt);
	},
	
	/**
     * Imposta lo store delle features.
     * @param {Ext.Data.Store} store Oggetto rappresentante lo store dei dati. 
     *
     */
	setFeatureStore: function(store){
		this.featureStore = store
		
		this.featureStore.on("load", function(){
			this.featureStore.pageSize = this.paginationSupported ? this.maxFeatures : this.dummyMaxFeature;
			this.fireEvent("loadfeatures");
		}, this);
	},
	
    /**
     * Recupera lo schema degli attributi.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
	getSchema: function(fparams){
		
		fparams.format = 'ext';
		
        if (!this.schemaCache) {
            this.schemaCache = {};
        }
        
        this.fireEvent("beforelayerchange");
        
        var schema = this.schemaCache[fparams.codTPN];
        if(schema){
			this.fireEvent("layerchange", schema);
        }else{
        	var submitOpt = {
        		url: this.TOLOMEOServer + this.TOLOMEOContext + '/FilterBuilderMetadataServlet',
        		method: 'POST',
        		params: fparams,
        		waitMsg: ToloI18n.getMsg("ToloFeatureManager.attesa"),
        		success: function(results, store){
        			var schema = results;
        			this.schemaCache[fparams.codTPN] = schema;        			
        			this.fireEvent("layerchange", results);
        		},
        		failure: this.doAjaxFailure,
        		scope: this
        	};
        	
    		new TolomeoExt.ToloCrossAjax().request(submitOpt);
        }        
	},
	
	/**
	 * Gestisce il caricamento del nuovo schema andando a verificare se la paginazione è supportata.
	 * @param {} schema
	 */
	onLayerChange: function(schema){
		if(schema[0] && schema[0].data){
			this.paginationSupported = schema[0].data.paginationSupported;
		} else {
			this.paginationSupported = false;
		}
	},
	
	/**
     * Handler invocato in caso di fallimento della richiesta Ajax.
     * @param {Ext.Data.Store} store Oggetto rappresentante lo store dei dati. 
     *
     */
	doAjaxFailure: function (store) {
		this.fireEvent("loadfeaturesfailure", store);
    },
    
    /**
     * Metodo di caricamento dello store delle features.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    loadFeatures: function(fparams){       	
    	//
    	// Prepare the proxy params
    	//
		this.proxy.extraParams = this.proxy.extraParams || {};
		this.proxy.startParam = "startIndex";
		this.proxy.limitParam = "maxFeatures";
		this.proxy.actionMethods = "POST";
		
    	Ext.apply(this.proxy.extraParams, fparams); 
    	
    	this.fireEvent("beforeloadfeatures",fparams.codTPN);
    	
    	this.featureStore.loadPage(1, {
    	    params:{
    	    	startIndex: this.startIndex,
    	    	maxFeatures: (this.paginationSupported ? this.maxFeatures : -1)
    	    }
    	});
    },
    
	/**
     * Imposta il proxy per le richieste cross-domain. 
     *
     */
    setProxy: function(){
		this.proxy = TolomeoExt.ToloCrossAjaxUtil.getProxy(null, this.TOLOMEOServer + this.TOLOMEOContext + '/SearchExportServlet');
		var reader = this.proxy.getReader();
		reader.root = "rows";
		reader.totalProperty = "total";
    },
    
    /**
     * Recupera il proxy usato per le richiesta cross-domani. 
     *
     */
    getProxy: function(){
    	return this.proxy;
    },
    
	/**
     * Reimposta i parametri di richiesta per la raccolta delle features risultato della ricerca. 
     *
     */
    resetQuery: function(collapse){
    	if(this.featureStore){
    		this.featureStore.removeAll();
    	}
		
    	this.fireEvent("resetfeaturelayer");
    }
	
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Strumento di ricerca alfanumerica libera 
 * (Query Tool) general purpose (in grado cioè di 
 * lavorare su qualunque layer vettoriale configurato 
 * nel sistema) per Tolomeo.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.ToloQueryBuilderExt', {

	extend: 'Ext.Panel',

	/**
	 * @cfg {Object} paramsJS
	 * Configurazioni specifiche del file di preset.
	 */
	paramsJS: null,

	/**
	 * @cfg {String} TOLOMEOServer
	 * URL di base del contesto di Tolomeo.
	 */
	TOLOMEOServer: null,

	/**
	 * @cfg {String} TOLOMEOContext
	 * Contesto di Tolomeo.
	 */
	TOLOMEOContext: null,
	
	/**
	 * @cfg {String} filterFormat [filterFormat="OGC"]
	 * Formato dei filtro. Possibili valori: "OGC", "CQL".
	 */
	filterFormat: "OGC",
	
	/**
	 * @cfg {String} ogcFilterVersion [ogcFilterVersion="1.1.0"]
	 * Se filterFormat="OGC" indica il numero di versione del filtro.
	 */
	ogcFilterVersion: "1.1.0",

	/**
	 * @cfg {Boolean} caseInsensitiveMatch [caseInsensitiveMatch="false"]
	 * Indica se i valori degli attributi nel filtro devono essere case sensitive o meno.
	 */
	caseInsensitiveMatch: false,
	
	config: {
		/**
		 * @cfg {TolomeoExt.ToloFeatureManager} qbFeatureManager (required)
		 * Gestore di richieste e operazioni che coinvolgono le features.
		 */
		qbFeatureManager: null,
		
		/**
		 * @cfg {TolomeoExt.events.ToloQueryBuilderEvtManager} qbEventManager (required)
		 * Gestore di eventi per il query builder.
		 */
		qbEventManager: null,
		
		/**
		 * @cfg {TolomeoExt.widgets.ToloLayerSelector} layerSelector
		 * 
		 */
		layerSelector: null,
		
		/**
		 * @cfg {TolomeoExt.widgets.ToloSpatialSelector} spatialSelector
		 * 
		 */
		spatialSelector: null,
		
		/**
		 * @cfg {TolomeoExt.widgets.ToloAttributeFilter} queryfilter
		 * 
		 */
		queryfilter: null
	}, 
	
	/**
	 * @cfg {Object} autoCompleteCfg [autoCompleteCfg="{}"]
	 * Contiene la configurazione per il servizio di autocompletamento.
	 *
	 * @example
	 * autoCompleteCfg: {
	 *  	url: 'http://localhost:8080/tolomeobinj/UniqueValueServlet',
	 *		pageSize: 10
	 * }
	 */
	autoCompleteCfg: {},
	
	/**
	 * @cfg {Boolean} [autoComplete="fase"]
	 * Abilita la funzionalità di autocomplete .
	 */
	autoComplete: false,
	
	/**
	 * @cfg {String} noFilterSelectedMsgTitle
	 * 
	 */
    noFilterSelectedMsgTitle: null,
    
	/**
	 * @cfg {String} noFilterSelectedMsgText
	 * 
	 */
    noFilterSelectedMsgText: null,
    
	/**
	 * @cfg {String} invalidRegexFieldMsgTitle
	 * 
	 */
    invalidRegexFieldMsgTitle: null,
    
	/**
	 * @cfg {String} invalidRegexFieldMsgText
	 * 
	 */
    invalidRegexFieldMsgText: null,
    
	/**
	 * @cfg {String} notEnabledFieldMsgTitle
	 * 
	 */
    notEnabledFieldMsgTitle: null,
    
    /**
	 * @cfg {Boolean} notEnabledFieldMsgText
	 * 
	 */
    notEnabledFieldMsgText: null,    

	/**
     * Inizializza un nuovo TolomeoExt.ToloQueryBuilderExt.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	initComponent: function(config){	
		TolomeoExt.Vars.ApplyIfDefaults(this);

		this.noFilterSelectedMsgTitle=ToloI18n.getMsg("ToloQueryBuilderExt.noFilterSelectedMsgTitle");
		this.noFilterSelectedMsgText=ToloI18n.getMsg("ToloQueryBuilderExt.noFilterSelectedMsgText");
		this.invalidRegexFieldMsgTitle=ToloI18n.getMsg("ToloQueryBuilderExt.invalidRegexFieldMsgTitle");
		this.invalidRegexFieldMsgText=ToloI18n.getMsg("ToloQueryBuilderExt.invalidRegexFieldMsgText");
		this.notEnabledFieldMsgTitle=ToloI18n.getMsg("ToloQueryBuilderExt.notEnabledFieldMsgTitle");
		this.notEnabledFieldMsgText=ToloI18n.getMsg("ToloQueryBuilderExt.notEnabledFieldMsgText");  
		
		this.autoScroll = true;
		this.collapsed = false;
    	
		if(!this.qbEventManager){
			this.qbEventManager = Ext.create('TolomeoExt.events.ToloQueryBuilderEvtManager');
		}
		
		if(!this.qbFeatureManager){
			this.qbFeatureManager = Ext.create('TolomeoExt.ToloFeatureManager', {
				TOLOMEOServer: this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext
			});
		}
		
		this.qbFeatureManager.on({
			scope: this,
			layerchange: function(results/*, store*/){
				this.waitMask.hide();
				this.queryfilter.addFilterBuilder(results/*, store*/);
				this.spatialSelector.setGeomFieldName(this.queryfilter.getGeomFieldName());
			},
			loadfeatures: function(results, store){
				this.waitMask.hide();
			},
			beforeloadfeatures: function(){
				this.waitMask.show();
			},
			beforelayerchange: function(){
				this.waitMask.show();
			},
			loadfeaturesfailure: function(){
				this.waitMask.hide();
			}
		});
		
		// /////////////////////
		// Layer Selector
		// /////////////////////
		var layers = [];
		var evetLayerList = this.paramsJS.azioniEventi.eventiLayerList;
		for(var i=0; i<evetLayerList.length; i++){
			var layerEventConfig = evetLayerList[i];
			if(layerEventConfig.queryBuilder){
				layers.push({
					name: layerEventConfig.nomeLayer, 
					description: layerEventConfig.descrizioneLayer, 
					codTPN: layerEventConfig.codTPN
				});
			}
		}
		
		this.layerSelector = Ext.create('TolomeoExt.widgets.ToloLayerSelector', {
			layers: layers,
			listeners:{
				scope: this,
				layerselected: function(records){
					this.reset();
					
					// /////////////////////////////////////////////////
					// Enable the sub components after layer selection
					// in order to allow filter composition.
					// /////////////////////////////////////////////////
					this.spatialSelector.enable();
					this.filterView.enable();
					this.enableAttributeFilter(records[0]);
				}				
			}
		});
		
		// /////////////////////
		// Spatial Selector
		// /////////////////////
		this.spatialSelector = Ext.create('TolomeoExt.widgets.ToloSpatialSelector', {
			qbEventManager: this.qbEventManager,
			filterGeometryName: "geom",
			disabled: true
		});
		
		// /////////////////////
		// Attribute Filter
		// /////////////////////
		this.queryfilter = Ext.create('TolomeoExt.widgets.ToloAttributeFilter', {
			scroll: true,
			disabled: true,
			caseInsensitiveMatch: this.caseInsensitiveMatch,
			autoCompleteCfg: this.autoCompleteCfg,
			autoComplete: this.autoComplete,
			TOLOMEOServer: this.TOLOMEOServer,
			TOLOMEOContext: this.TOLOMEOContext
		});
		
		this.filterView = Ext.create('TolomeoExt.widgets.ToloFilterView', {
			scroll: true,
			disabled: true,
			listeners:{
				scope: this,
				typeselected: function(records){
					var filter = this.getFilter();
					if(filter){
						var record = records;
						
						if(records instanceof Array){
							record = records[0];
						}
						
						var serialized_filter = this.getFilterString(filter, record.get("name"));
						this.filterView.setFilter(serialized_filter);
					}
				}
			}
		});
			
		this.bbar = ["->", {
            text: "Cancella",
            iconCls: "querybuilder-icon-cancel",
            scope: this,
            handler: function() {
            	this.resetAllConditions();
            }
        }, {
            text: "Cerca",
            iconCls: "querybuilder-icon-find",
            handler: function() {
            	var filter = this.getFilter();
            	
            	if(filter){
            		var serialized_filter = this.getFilterString(filter, null);

                    var fparams = {
        				codTPN: this.codTPN,
        				SRID: this.paramsJS.mappe.SRID,
        				filter: serialized_filter,
        				ogcFilterVersion: this.ogcFilterVersion,
        				format: "ext"
        			}; 
            		
                    this.qbFeatureManager.loadFeatures(fparams);
            	}
            },
            scope: this
        }];
		
		this.callParent();
	
		this.add([this.layerSelector, this.spatialSelector, this.queryfilter, this.filterView]);
		
		this.spatialSelector.reset();
		
		// ////////////////////////////////////////////////////////
		// Disable the tool if any layer is configured to use it
		// ////////////////////////////////////////////////////////
		if(layers.length < 1){
			this.disabled = true;
		}
		
		this.on("afterrender", function(){
			this.waitMask = new Ext.LoadMask(this.id, {msg: "Ricerca in corso...."});
		}, this);
		
	},
	
	/**
     * Reimposta i componenti della form e il la griglia delle features
     *
     */
	reset: function(){
		
		// Attribute Form Reset
    	this.queryfilter.attributeFieldSet.removeAll();
		this.resetAllConditions();		    	
    	    	    	    
	},
	
	/**
     * Reimposta tutte le condizioni iniziali di ricerca per lo specifico livello
     *
     */
	resetAllConditions: function(){
    	// Spatial Selector Reset
    	this.spatialSelector.reset();
    	var spatialMethodCombo = this.spatialSelector.getSelectionMethodCombo();
    	spatialMethodCombo.reset();
    	
    	// Attribute Form Reset
    	if(this.queryfilter.filterBuilder){
    		this.queryfilter.filterBuilder.removeAllConditions();
    	}
    	
    	
    	// Attribute Filter Reset
    	this.filterView.resetView();
    	
    	// Feature Grid Reset
    	this.qbFeatureManager.fireEvent("resetquery");
	},
	
	/**
     * Abilita il filtro degli attributi.
     * @param {Ext.Data.Record} record corrispondente al layer selezionato. 
     *
     */
	enableAttributeFilter: function(record){
		// Adding a Filter Builder passing the feature type name
		this.codTPN = record.get('codTPN');
		
		var fparams = {
			codTPN: this.codTPN
		}; 
		
    	// Submit ajax della form
    	this.qbFeatureManager.getSchema(fparams);
	},
	
	/**
     * Recupera il filtro selezionato in formato stringa.
     * @param {OpenLayers.Filter} filter Il filtro selezionato. 
	 * @param {String} type Tipo del filtro.
     * @return {String} il filtro in formato stringa.
     */
	getFilterString: function(filter, type){
        var format = this.filterFormat;        
        if(type){
        	format = type;
        }
        
        var serialized_filter = "";
        if(format == "OGC" ){
            var node = new OpenLayers.Format.Filter({version: this.ogcFilterVersion}).write(filter);
            serialized_filter = new OpenLayers.Format.XML().write(node);
        }else{
        	serialized_filter = new OpenLayers.Format.CQL().write(filter);
        }
        
        return serialized_filter;
	},
	
    /**
     * Recupera il filtro selezionato.
     * @return {OpenLayers.Filter} il filtro selezionato.
     */
	getFilter: function(){
		var filter = null;
								
    	if(!this.queryfilter.disabled && !this.spatialSelector.disabled){
    		
    		if(this.queryfilter.attributeFieldSet.collapsed && this.spatialSelector.spatialFieldSet.collapsed){
    			
    			 Ext.Msg.show({
    				 title: this.noFilterSelectedMsgTitle,
                     msg: this.noFilterSelectedMsgText,
                     buttons: Ext.Msg.OK,
                     icon: Ext.MessageBox.ERROR
                 }); 
    			
    			return filter;
    		}
    		
    		// ////////////////////////////////////////////////
            // Check if there are some invalid field according 
    		// to validators regex config
            // ////////////////////////////////////////////////
    		var invalidItems = 0;
    		if(!this.queryfilter.attributeFieldSet.collapsed){
        		var filterFieldItem = this.query('tolomeo_tolofilterfield');            

                for(var x = 0; x<filterFieldItem.length; x++){
                	if(filterFieldItem[x].valueWidgets){
                    	var valueWidgets = filterFieldItem[x].valueWidgets.items.items;
                    	for(var y=0; y<valueWidgets.length; y++){
                    		var validateItem = valueWidgets[y];
                            if(!validateItem.isValid(true)){
                                invalidItems++;
                            }
                    	}
                	}
                }  
    		}
            
            if(invalidItems == 0){                    	
            	var filters = [];
            	
            	// ///////////////////////
            	// Compose the Filter
            	// ///////////////////////
            	if(!this.queryfilter.attributeFieldSet.collapsed){
                	var attributeFilter = this.queryfilter.filterBuilder.getFilter();
                	if(attributeFilter){
                		filters.push(attributeFilter);	
                	}
            	}

            	// /////////////////////////////////////////////
            	// If the spatial field set is collapdes then 
            	// use the current map extent. 
            	// /////////////////////////////////////////////
            	var currentMapExtent = this.spatialSelector.spatialFieldSet.collapsed;
            	if(!currentMapExtent){
	                var spatialFilter = this.spatialSelector.getQueryFilter(currentMapExtent);   
	                if (spatialFilter) {
	                	spatialFilter.projection = this.paramsJS.mappe.SRID;
	                	filters.push(spatialFilter);
	                }
            	}
            	
                if(filters.length > 0){
    				var filter = filters.length > 1 ?
                        new OpenLayers.Filter.Logical({
                            type: OpenLayers.Filter.Logical.AND,
                            filters: filters
                        }) :
                        filters[0];   
                        
                    return filter;
                    
                }else{
                    Ext.Msg.show({
                        title: this.noFilterSelectedMsgTitle,
                        msg: this.noFilterSelectedMsgText,
                        buttons: Ext.Msg.OK,
                        icon: Ext.MessageBox.ERROR
                    }); 
                }
            }else{
                Ext.Msg.show({
                    title: this.invalidRegexFieldMsgTitle,
                    msg: this.invalidRegexFieldMsgText,
                    buttons: Ext.Msg.OK,
                    icon: Ext.MessageBox.ERROR
                });
            }
            
    	}else {
            Ext.Msg.show({
                title: this.notEnabledFieldMsgTitle,
                msg: this.notEnabledFieldMsgText,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR
            });
    	}
    	
    	return filter;
	}
    
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets');

/**
 * Crea il pannello contenitore per il filtro degli attributi.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.ToloAttributeFilter', {

	extend: 'Ext.Panel',
	
	padding: '0 5 0 5',
	
	/**
     * @cfg {Boolean} caseInsensitiveMatch [caseInsensitiveMatch="false"]
	 * Il filtro di comparazione per i campi di tipo stringa deve essere case insensitive ?
     */
	caseInsensitiveMatch: false,
    
	/**
     * @cfg {Object} autoCompleteCfg [autoCompleteCfg="{}"]
	 * Stabilisce la configurazione da usare per la funzionalità di autocompletamento.
	 *
	 * @example
	 * autoCompleteCfg: {
	 *  	url: 'http://localhost:8080/tolomeobinj/UniqueValueServlet',
	 *		pageSize: 10
	 * }
     */
	autoCompleteCfg: {},
	
	/**
     * @cfg {Boolean} autoComplete [autoComplete="false"]
	 * Abilita la funzionalità di autocompletamento per i campi stringa.
     */
	autoComplete: false,
	
	filterBuilderStore: null,

	/**
     * Inizializza un nuovo TolomeoExt.widgets.ToloAttributeFilter.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	initComponent: function(config){				
		this.border = 0;
		
		this.attributeFieldSet = Ext.create('Ext.form.FieldSet', {
			title: ToloI18n.getMsg("ToloAttributeFilter.attributeFieldSet"),
			//anchor: "-1",
			autoWidth: true,
			autoHeight: true,
			collapsed : true,
			checkboxToggle: true
		});
		
		this.items = [this.attributeFieldSet];
        
		this.callParent();
    },
    
    getGeomFieldName: function() {
    	var fields = this.filterBuilderStore.model.getFields();
    	for (var i=0; i<fields.length; i++){
    		var field = fields[i];
    		if (field.name=="geomFieldName"){
    			geomFieldName = field.mapping;
    			break;
    		}
    	}
    	return this.filterBuilderStore.getAt(0).get("geomFieldName");
    },
    
	/**
     * Aggiunge alla form un nuovo nuovo costruttore per il filtro.
     * @param {Array} records corrispondenti allo schema della FeatureType da gestire.
     */
    addFilterBuilder: function(results){
    	
    	var schema = results;
    	this.filterBuilderStore = Ext.create('Ext.data.Store', {
   		    fields: [{
   		    	name: 'name',
   		    	mapping: 'name'
   		    },{
   		    	name: 'type', 
   		    	mapping: 'type'
   		    },{
   		    	name: 'restriction', 
   		    	mapping: 'restriction'
   		    },{
   		    	name: 'regex', 
   		    	mapping: 'regex'
   		    },{
   		    	name: 'dbname', 
   		    	mapping: 'dbname'
   		    },{
   		    	name: 'codTPN', 
   		    	mapping: 'codTPN'
   		    },{
   		    	name: 'geomFieldName', 
   		    	mapping: 'geomFieldName'
   		    },{
	   		    name: 'autocomplete', 
	   		    mapping: 'autocomplete'
	   		}],
   		    data: schema
   		});
    	
		this.filterBuilder = new TolomeoExt.widgets.ToloFilterBuilder({
			 caseInsensitiveMatch: this.caseInsensitiveMatch,
			 autoCompleteCfg: this.autoCompleteCfg,
			 autoComplete: this.autoComplete,
			 TOLOMEOServer: this.TOLOMEOServer,
			 TOLOMEOContext: this.TOLOMEOContext,
			 attributes: this.filterBuilderStore,
            allowBlank: true,
            allowGroups: false
        });
		
		this.attributeFieldSet.add(this.filterBuilder);
		
		this.enable();
    },
    
    reset: function(){
    	if(this.filterBuilder){
    		this.filterBuilder.removeAllConditions();
    	}
    	this.attributeFieldSet.removeAll();
    }
    
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets');

/**
 * Crea un panello per assembrale la form di composizione del filtro.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.ToloFilterBuilder', {
	
	extend: 'Ext.Container',

	alias: 'widget.tolomeo_tolofilterbuilder',

	padding: '0 5 0 5',
	
	/**
     * @cfg {Array} builderTypeNames [builderTypeNames=``["ognuno", "tutti", "nessuno", "non tutti"]``]
	 * La lista di etichette che corrispondono ai tipi di costanti del costruttore.
     */
	builderTypeNames: null,
    
	/**
     * @cfg {Array} allowedBuilderTypes 
	 * La lista delle costanti dei tipi di costruttore. Valori possibili sono ``[ANY_OF, ALL_OF, NONE_OF]``
     */
    allowedBuilderTypes: null,

	/**
     * @cfg {Boolean} allowBlank [allowBlank="false"]
	 * Impostare a true se si desidera consentire campi vuoti.
     */
    allowBlank: false,

	/**
     * @cfg {Boolean} caseInsensitiveMatch [caseInsensitiveMatch="false"]
	 * Il filtro di comparazione per i campi di tipo stringa deve essere case insensitive ?
     */
    caseInsensitiveMatch: false,

	/**
     * @cfg {String} preComboText
	 * Testo da mostrare prima della combo box per il tipo.
     */
    preComboText: null,

    /**
     * @cfg {String} postComboText
	 * Testo da mostrare dopo la combo box per il tipo.
     */
    postComboText: null,

	/**
     * @cfg {String} cls
	 * La classe di stile da usare per i pannelli di questo componente.
     */
    cls: "tolomeo-tolofilterbuilder",

	/**
     * @property {Object} builderType
	 * 
     */
    builderType: null,

	/**
     * @property {Object} childFilterContainer
	 * 
     */
    childFilterContainer: null,
    
	/**
     * @cfg {Object} customizeFilterOnInit [customizeFilterOnInit="true"]
	 * 
     */
    customizeFilterOnInit: true,
    
    /**
     * @cfg {String} addConditionText
	 * 
     */
    addConditionText: null,
	
	/**
     * @cfg {String} addGroupText
	 * 
     */
    addGroupText: null,
	
	/**
     * @cfg {String} removeConditionText
	 * 
     */
    removeConditionText: null,

	/**
     * @cfg {Boolean} allowGroups [customizeFilterOnInit="false"]
	 * Consente di agiungere gruppi di condizioni. Se "false" solo condizioni individuali saranno aggiunte al filtro.
     */
    allowGroups: false,
    
	/**
     * @cfg {Object} attributesComboConfig 
	 * Configurazione della combo box degli attributi.
     */
    attributesComboConfig: null,

	/**
     * @cfg {Boolean} autoComplete [autoComplete="false"]
	 * Abilita la funzionalità di autocompletamento per i campi stringa.
     */
    autoComplete: false,
    
	/**
     * @cfg {Object} autoCompleteCfg [autoCompleteCfg="{}"]
	 * Stabilisce la configurazione da usare per la funzionalità di autocompletamento.
	 *
	 * @example
	 * autoCompleteCfg: {
	 *  	url: 'http://localhost:8080/tolomeobinj/UniqueValueServlet',
	 *		pageSize: 10
	 * }
     */
    autoCompleteCfg: {},

	/**
     * Inizializza un nuovo TolomeoExt.widgets.ToloFilterBuilder.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config) {
        var defConfig = {
            defaultBuilderType: TolomeoExt.widgets.ToloFilterBuilder.ANY_OF
        };
        Ext.applyIf(this, defConfig);
        
        
        this.allowedBuilderTypes = [ToloI18n.getMsg("ToloFilterBuilder.builderTypeNames.unoquasiasi"), 
    		ToloI18n.getMsg("ToloFilterBuilder.builderTypeNames.tutti"),
    		ToloI18n.getMsg("ToloFilterBuilder.builderTypeNames.nessuno"),
    		ToloI18n.getMsg("ToloFilterBuilder.builderTypeNames.nontutti")];
        
        this.preComboText = ToloI18n.getMsg("ToloFilterBuilder.preComboText");
        this.postComboText = ToloI18n.getMsg("ToloFilterBuilder.postComboText");
        
        this.addConditionText = ToloI18n.getMsg("ToloFilterBuilder.addConditionText");
        this.addGroupText = ToloI18n.getMsg("ToloFilterBuilder.addGroupText");
        this.removeConditionText = ToloI18n.getMsg("ToloFilterBuilder.removeConditionText");
        
        if(this.customizeFilterOnInit) {
            this.filter = this.customizeFilter(this.filter);
        }
        
        this.builderType = this.getBuilderType();
        
        this.items = [{
            xtype: "container",
            layout: "form",
            ref: "form",
            defaults: {anchor: "100%"},
            hideLabels: true,
            items: [
                {
	                xtype: "fieldcontainer",
	                style: "padding-left: 2px",
	                items: [{
	                    xtype: "label",
	                    style: "padding-top: 0.3em",
	                    text: this.preComboText
	                }, this.createBuilderTypeCombo(), 
	                {
	                    xtype: "label",
	                    style: "padding-top: 0.3em",
	                    text: this.postComboText
	                }]
	            }, 
	            this.createChildFiltersPanel(), 
	            {
	                xtype: "toolbar",
	                items: this.createToolBar()
	            }
		    ]        
        }];
        
        this.addEvents(
			/**
			 * @event
			 * Lanciato quando il filtro subisce un cambiamento.
			 */
            "change"
        ); 

        this.callParent();
        
        this.on("added", function(scope){
        	scope.form = scope.query('container[ref=form]')[0];
        	scope.builderTypeCombo = scope.query('combo[ref=builderTypeCombo]')[0];
        });
    },

	/**
     * Crea la toolbar di comando.
     *
     */
    createToolBar: function() {
        var bar = [{
            text: this.addConditionText,
            iconCls: "add",
            handler: function() {
                this.addCondition();
            },
            scope: this
        }];
        if(this.allowGroups) {
            bar.push({
                text: this.addGroupText,
                iconCls: "add",
                handler: function() {
                    this.addCondition(true);
                },
                scope: this
            });
        }
        return bar;
    },
    
	/**
     * Restituisce il filtro che corrisponde al modello delle specifiche di Filter Encoding.
	 * Usare questo metodo invece che accedere direttamente alla proprietà ``filter`` della proprità.
	 * Il valore di ritorno sarà ``false`` se nessun figlio possiede una proprietà, un typo o un valore.
     * @return {OpenLayers.Filter} Il filtro corrente.
     */
    getFilter: function() {
        var filter;
        if(this.filter) {
            filter = this.filter.clone();
            if(filter instanceof OpenLayers.Filter.Logical) {
                filter = this.cleanFilter(filter);
            }
        }
        return filter;
    },
    
	/**
     * Assicura che i filtri binary logici abbiano più di un figlio.
     * @param {OpenLayers.Filter.Logical} filter Il filtro corrente.
	 * @return {OpenLayers.Filter} Un filtro che rispetta il modello usato da questo costruttore.
     */
    cleanFilter: function(filter) {
        if(filter instanceof OpenLayers.Filter.Logical) {
            if(filter.type !== OpenLayers.Filter.Logical.NOT &&
               filter.filters.length === 1) {
                filter = this.cleanFilter(filter.filters[0]);
            } else {
                var child;
                for(var i=0, len=filter.filters.length; i<len; ++i) {
                    child = filter.filters[i];
                    if(child instanceof OpenLayers.Filter.Logical) {
                        child = this.cleanFilter(child);
                        if(child) {
                            filter.filters[i] = child;
                        } else {
                            filter = child;
                            break;
                        }
                    } else if(!child || child.type === null || child[child.property] === null || child[child.type === OpenLayers.Filter.Comparison.BETWEEN ? "lowerBoundary" : "value"] === null || child[child.type === OpenLayers.Filter.Comparison.BETWEEN ? "upperBoundary" : "value"] === null ) {
                        filter = false;
                        break;
                    }
                }
            }
        } else {
            if(!filter || filter.type === null || filter.property === null || filter[filter.type === OpenLayers.Filter.Comparison.BETWEEN ? "lowerBoundary" : "value"] === null || filter[filter.type === OpenLayers.Filter.Comparison.BETWEEN ? "upperBoundary" : "value"] === null) {
                filter = false;
            }
        }
        return filter;
    },
    
	/**
     * Crea un filtro che corrisponde al modello del corrente costruttore.
	 * Questo filtro non rispetterà necessariamente e specifiche di Filter Encoding.
	 * In particolare, i filtri che rappresentano operatori logici binary possono non avere due filtri figlio.
	 * Usare il metodo ''getFilter'' per ottenere un filtro che rispetta le specifiche di Filter Encoding
     * @param {OpenLayers.Filter} filter Il filtro corrente.
	 * @return {OpenLayers.Filter} Un filtro che rispetta il modello usato da questo costruttore.
     */
    customizeFilter: function(filter) {
        if(!filter) {
            filter = this.wrapFilter(this.createDefaultFilter());
        } else {
            filter = this.cleanFilter(filter);
            var child, i, len;
            switch(filter.type) {
                case OpenLayers.Filter.Logical.AND:
                case OpenLayers.Filter.Logical.OR:
                    if(!filter.filters || filter.filters.length === 0) {
                        // give the filter children if it has none
                        filter.filters = [this.createDefaultFilter()];
                    } else {
                        for(i=0, len=filter.filters.length; i<len; ++i) {
                            child = filter.filters[i];
                            if(child instanceof OpenLayers.Filter.Logical) {
                                filter.filters[i] = this.customizeFilter(child);
                            }
                        }
                    }
                    // wrap in a logical OR
                    filter = new OpenLayers.Filter.Logical({
                        type: OpenLayers.Filter.Logical.OR,
                        filters: [filter]
                    });
                    break;
                case OpenLayers.Filter.Logical.NOT:
                    if(!filter.filters || filter.filters.length === 0) {
                        filter.filters = [
                            new OpenLayers.Filter.Logical({
                                type: OpenLayers.Filter.Logical.OR,
                                filters: [this.createDefaultFilter()]
                            })
                        ];
                    } else {
                        // NOT filters should have one child only
                        child = filter.filters[0];
                        if(child instanceof OpenLayers.Filter.Logical) {
                            if(child.type !== OpenLayers.Filter.Logical.NOT) {
                                // check children of AND and OR
                                var grandchild;
                                for(i=0, len=child.filters.length; i<len; ++i) {
                                    grandchild = child.filters[i];
                                    if(grandchild instanceof OpenLayers.Filter.Logical) {
                                        child.filters[i] = this.customizeFilter(grandchild);
                                    }
                                }
                            } else {
                                // silly double negative
                                if(child.filters && child.filters.length > 0) {
                                    filter = this.customizeFilter(child.filters[0]);
                                } else {
                                    filter = this.wrapFilter(this.createDefaultFilter());
                                }
                            }
                        } else {
                            // non-logical child of NOT should be wrapped
                            var type;
                            if(this.defaultBuilderType === TolomeoExt.widgets.ToloFilterBuilder.NOT_ALL_OF) {
                                type = OpenLayers.Filter.Logical.AND;
                            } else {
                                type = OpenLayers.Filter.Logical.OR;
                            }
                            filter.filters = [
                                new OpenLayers.Filter.Logical({
                                    type: type,
                                    filters: [child]
                                })
                            ];
                        }
                    }
                    break;
                default:
                    // non-logical filters get wrapped
                    filter = this.wrapFilter(filter);
                    break;
            }
        }
        return filter;
    },
	
	/**
     * Inizializza il filtro predefinito.
	 * @return {OpenLayers.Filter} Un filtro che rispetta il modello usato da questo costruttore.
     */
    createDefaultFilter: function() {
        return new OpenLayers.Filter.Comparison({
                            matchCase: !this.caseInsensitiveMatch});
    },
    
	/**
     * Prende un filtro non logico per creare un parent che dipende da ``defaultBuilderType``.
	 * @param {OpenLayers.Filter} filter Un filtro non logico.
	 * @return {OpenLayers.Filter} Una versione wrapped del filtro passato come argomento.
     */
    wrapFilter: function(filter) {
        var type;
        if(this.defaultBuilderType === TolomeoExt.widgets.ToloFilterBuilder.ALL_OF) {
            type = OpenLayers.Filter.Logical.AND;
        } else {
            type = OpenLayers.Filter.Logical.OR;
        }
        return new OpenLayers.Filter.Logical({
            type: OpenLayers.Filter.Logical.OR,
            filters: [
                new OpenLayers.Filter.Logical({
                    type: type, filters: [filter]
                })
            ]
        });
    },
    
	/**
     * Aggiunge una nuova condizione o gruppo di condizion al costruttore del filtro.
	 * Qusto modifica il filtro a aggiunge un pannello che rappresenta la nuova condizione 
	 * o grupo di condizioni.
	 * @param {Object} group Un nuovo gruppo di condizioni.
     */
    addCondition: function(group) {
        var filter, type;
        if(group) {
            type = "tolomeo_tolofilterbuilder";
            filter = this.wrapFilter(this.createDefaultFilter());
        } else {
            type = "tolomeo_tolofilterfield";
            filter = this.createDefaultFilter();
        }
        var newChild = this.newRow({
            xtype: type,
            filter: filter,
            columnWidth: 1,
            attributes: this.attributes,
            autoComplete: this.autoComplete,
            autoCompleteCfg: this.autoCompleteCfg,
			TOLOMEOServer: this.TOLOMEOServer,
			TOLOMEOContext: this.TOLOMEOContext,
            allowBlank: group ? undefined : this.allowBlank,
            customizeFilterOnInit: group && false,
            caseInsensitiveMatch: this.caseInsensitiveMatch,
            listeners: {
                change: function() {
                    this.fireEvent("change", this);
                },
                scope: this
            }
        });
        this.childFilterContainer.add(newChild);
        this.filter.filters[0].filters.push(filter);
        this.childFilterContainer.doLayout();
    },
    
	/**
     * Rimuove una condizione o gruppo di condizioni da costruttore. 
	 * Questo modificha il filtro e rimuove il pannello che rappresenta la nuova condizione 
	 * o grupo di condizioni.
	 * @param {Object} item elemento da rimuovere.
	 * @param {OpenLayers.Filter} filter Il filtro corrente .
     */
    removeCondition: function(item, filter) {
		var parent = this.filter.filters[0].filters;
		if(parent.length > 1) {
			var a = parent.indexOf(filter);
			if(a!=-1){
				parent.splice(a,1)
			}
			
			this.childFilterContainer.remove(item, true);
		}else{
			var items = item.query("tolomeo_tolofilterfield");
			
			var i = 0;
			while(items[i]){
				for(var k = 0; k<items.length; k++){
					items[k].items.each(function(f) {
					    if (Ext.isFunction(f.reset)) {
					        f.reset();
					    }
					});
				}
				
                for(var c = 1;c<items[i].items.items.length;c++){
                	var cmp = items[i].items.get(c);
                	if(cmp.xtype == "container"){
                		cmp.removeAll();
                	}else{
                		cmp.disable();
                	}
                }

				filter.value = null;
                filter.lowerBoundary = null;
                filter.upperBoundary = null;
				i++;
			}
		}
		
		this.fireEvent("change", this);
    },
    
	/**
     * Rimuove dal pannello tutte le condizioni presenti.
     * 
     */
    removeAllConditions: function(){
    	var containers = this.query("container[name=filtercondition_container]");
    	for(var i=0; i<containers.length; i++){
    		var container = containers[i];
    		var filter = container.items.items[1].filter;
    		this.removeCondition(container, filter);
    	}    	
    },
    
    /**
     * Crea la combo box corrispondente ai tipi di costruttore possibili per il filtro.
	 *
     */
    createBuilderTypeCombo: function() {
        var types = this.allowedBuilderTypes || [
            TolomeoExt.widgets.ToloFilterBuilder.ANY_OF, 
            TolomeoExt.widgets.ToloFilterBuilder.ALL_OF,
            TolomeoExt.widgets.ToloFilterBuilder.NONE_OF
        ];
        var numTypes = types.length;
        var data = new Array(numTypes);
        var type;
        for(var i=0; i<numTypes; ++i) {
            type = types[i];
            data[i] = [type, this.builderTypeNames[type]];
        }
        return {
            xtype: "combo",
            store: new Ext.data.SimpleStore({
                data: data,
                fields: ["value", "name"]
            }),
            value: this.builderType,
            ref: "builderTypeCombo",
            displayField: "name",
            valueField: "value",
            triggerAction: "all",
            queryMode: "local",
            listeners: {
                select: function(combo, records) {
                	var record = records;
                	if(records instanceof Array){
                		record = records[0];
                	}
                    this.changeBuilderType(record.get("value"));
                    this.fireEvent("change", this);
                },
                scope: this
            },
            width: 100
        };
    },

	/**
     * Altera i tipi di filtroquando la combo dei tipi di filtro cambia di valore.
	 * @param {Integer} type elemento da rimuovere.
     */
    changeBuilderType: function(type) {
        if(type !== this.builderType) {
            this.builderType = type;
            var child = this.filter.filters[0];
            switch(type) {
                case TolomeoExt.widgets.ToloFilterBuilder.ANY_OF:
                    this.filter.type = OpenLayers.Filter.Logical.OR;
                    child.type = OpenLayers.Filter.Logical.OR;
                    break;
                case TolomeoExt.widgets.ToloFilterBuilder.ALL_OF:
                    this.filter.type = OpenLayers.Filter.Logical.OR;
                    child.type = OpenLayers.Filter.Logical.AND;
                    break;
                case TolomeoExt.widgets.ToloFilterBuilder.NONE_OF:
                    this.filter.type = OpenLayers.Filter.Logical.NOT;
                    child.type = OpenLayers.Filter.Logical.OR;
                    break;
                case TolomeoExt.widgets.ToloFilterBuilder.NOT_ALL_OF:
                    this.filter.type = OpenLayers.Filter.Logical.NOT;
                    child.type = OpenLayers.Filter.Logical.AND;
                    break;
            }
        }
    },

	/**
     * Crea il pannello che ospita tutte le condizioni e i gruppi di condizioni.
	 * Dato che questo è chiamato dopo che il filtro è stato personalizzato, noi abbiamo sempre 
     * un filtro logico con un filtro figlio che è un filtro logico. 	 
	 * @param {Integer} type elemento da rimuovere.
	 * @return {Ext.Container} il pannello contenitore.
     */
    createChildFiltersPanel: function() {
        this.childFilterContainer = new Ext.Container();
        var grandchildren = this.filter.filters[0].filters;
        var grandchild;
        for(var i=0, len=grandchildren.length; i<len; ++i) {
            grandchild = grandchildren[i];
            var fieldCfg = {
                xtype: "tolomeo_tolofilterfield",
                allowBlank: this.allowBlank,
                columnWidth: 1,
                filter: grandchild,
                attributes: this.attributes,
                autoComplete: this.autoComplete,
                autoCompleteCfg: this.autoCompleteCfg,
				TOLOMEOServer: this.TOLOMEOServer,
				TOLOMEOContext: this.TOLOMEOContext,
                caseInsensitiveMatch: this.caseInsensitiveMatch,
                listeners: {
                    change: function() {
                        this.fireEvent("change", this);
                    },
                    scope: this
                }
            };
            var containerCfg = Ext.applyIf(
                grandchild instanceof OpenLayers.Filter.Logical ?
                    {
                        xtype: "tolomeo_tolofilterbuilder"
                    } : {
                        xtype: "container",
                        layout: "form",
                        hideLabels: true,
                        items: fieldCfg
                    }, fieldCfg
            );
                
            this.childFilterContainer.add(this.newRow(containerCfg));
        }
        
        return this.childFilterContainer;
    },

	/**
     * Genera una nuova condizione per il filtro figlio del pannello. Questo accoppia 
	 * un altro pannello filtro o costruttore di filtro con un componente che consente la rimozione.	 
	 * @param {Ext.Container} filterContainer Il pannello contenitore degli elementi del filtro.
	 * @return {Ext.Container} il pannello contenitore della nuova condizione del filtro.
     */
    newRow: function(filterContainer) {
        var ct = Ext.create('Ext.Container', {
            layout: "column",
            name: "filtercondition_container",
            items: [
                {
	                xtype: "container",
	                width: 28,
	                height: 26,
	                style: "padding-left: 2px",
	                items: [{
	                    xtype: "button",
	                    style: {
	                    	marginTop: '3px'
	                    },
	                    tooltip: this.removeConditionText,
	                    iconCls: "delete",
	                    handler: function(btn){
	                        this.removeCondition(ct, filterContainer.filter);
	                    },
	                    scope: this
	                }]
	            }, filterContainer
            ]
        });
        return ct;
    },

	/**
     * Determina il tipo di costruttore basato sul filtro corrente.	 
	 * @return {Object} il tipo di costruttore.
     */
    getBuilderType: function() {
        var type = this.defaultBuilderType;
        if(this.filter) {
            var child = this.filter.filters[0];
            if(this.filter.type === OpenLayers.Filter.Logical.NOT) {
                switch(child.type) {
                    case OpenLayers.Filter.Logical.OR:
                        type = TolomeoExt.widgets.ToloFilterBuilder.NONE_OF;
                        break;
                    case OpenLayers.Filter.Logical.AND:
                        type = TolomeoExt.widgets.ToloFilterBuilder.NOT_ALL_OF;
                        break;
                }
            } else {
                switch(child.type) {
                    case OpenLayers.Filter.Logical.OR:
                        type = TolomeoExt.widgets.ToloFilterBuilder.ANY_OF;
                        break;
                    case OpenLayers.Filter.Logical.AND:
                        type = TolomeoExt.widgets.ToloFilterBuilder.ALL_OF;
                        break;
                }
            }
        }
        
        return type;
    },

	/**
     * Cambia il filtro associato a questa istanza del costruttore.	 
	 * @param {OpenLayers.Filter} filter Un filtro da impostare.
     */
    setFilter: function(filter) {
        this.filter = this.customizeFilter(filter);
        this.changeBuilderType(this.getBuilderType());
        this.builderTypeCombo.setValue(this.builderType);
        this.form.remove(this.childFilterContainer);
        this.form.insert(1, this.createChildFiltersPanel());
        this.form.doLayout();
        this.fireEvent("change", this);
    }

});

// //////////////////////////////////////////
// Tipi di costruttore
// //////////////////////////////////////////
TolomeoExt.widgets.ToloFilterBuilder.ANY_OF = 0;
TolomeoExt.widgets.ToloFilterBuilder.ALL_OF = 1;
TolomeoExt.widgets.ToloFilterBuilder.NONE_OF = 2;
TolomeoExt.widgets.ToloFilterBuilder.NOT_ALL_OF = 3;
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets');

/**
 * Widget per la visualizzazione del filtro impostato dall'utente nella form.
 * Le modifiche apportate dall'untente al filtro sono formattate in formato stringa.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.ToloFilterView', {

	extend: 'Ext.Panel',
	
	padding: '0 5 0 5',

	/**
     * Inizializza un componente di tipo TolomeoExt.widgets.ToloFilterView.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	initComponent: function(config){	
		this.border = 0;
			
		this.filterTypeStore = Ext.create('Ext.data.Store', {
		    fields: [{
		    	name: 'type', 
		    	mapping: 'type'
		    },{
		    	name: 'name', 
		    	mapping: 'name'
		    }],
		    data: [
	           {type: 1, name: "OGC"},
	           {type: 2, name: "CQL"}
		    ]
		});

		this.filterTypeCombo = Ext.create('Ext.form.ComboBox', {
			typeAhead: true,
			forceSelection: true, 
			width: 200,
			queryMode: 'local',
			triggerAction: 'all',
			selectOnFocus: true,
			editable: false,
			fieldLabel: ToloI18n.getMsg("ToloFilterView.filterTypeCombo"),
			name: 'name',
			value: 1,
			valueField: 'type',
			displayField: 'name',
			store: this.filterTypeStore,
		    listeners:{
		         scope: this,
		         select: function(combo, records, eOpts){
		        	 this.fireEvent("typeselected", records);
		         }
		    }
		});	
		
		this.filterView = Ext.create('Ext.form.TextArea', {
			flex: 1,
	        xtype: 'textareafield',
	        grow: true,
	        name: 'filterView',
	        fieldLabel: ToloI18n.getMsg("ToloFilterView.filterView"),
	        anchor: '100%',
	        labelAlign: "top",
	        height: 100
	    });
		
		var viewContainer = Ext.create('Ext.Panel', {
			border: false,
			height: 120,
		    layout: {
		        type: 'hbox',
		        align: 'middle'
		    },
		    items: [
	            this.filterView,
	            {
			        xtype: 'button',
			        iconCls: "filterviewupdate",
//			        style: "padding-top: 20px;",
			        tooltip: ToloI18n.getMsg("ToloFilterView.btnAggiorna"),
			        handler: function(button){
			        	var selectedRecord = this.filterTypeCombo.findRecordByValue(this.filterTypeCombo.getValue());
			        	this.fireEvent("typeselected", selectedRecord);
			        },
			        scope: this
			    }
	        ]
		});
				
		this.filterViewFieldSet = Ext.create('Ext.form.FieldSet',{
			title: ToloI18n.getMsg("ToloFilterView.filterViewFieldSet"),
			anchor: "-1",
			autoWidth: true,
			autoHeight: true,
			collapsed : true,
			checkboxToggle: true,
			items:[this.filterTypeCombo, viewContainer]
		});
		
		this.callParent();
		
		this.add(this.filterViewFieldSet);
    },
    
	/**
     * Imposta all'interno della TextArea definita la stringa corispondente il filtro selezionato.
     * @param {String} filterString Il filtro in formato stringa.
     */
    setFilter: function(filterString){
    	this.filterView.setRawValue(filterString);
    },
    
	/**
     * Reimposta la TextArea contenente il filro in formato stringa.
     *
     */
    resetView: function(){
    	this.filterView.setRawValue("");
    	this.filterTypeCombo.reset();
    }
    
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets');

/**
 * Widget per la selezione dei layers per cui il plugin query form è abilitato all'uso.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.ToloLayerSelector', {

	extend: 'Ext.Panel',
	
	/**
	 * @cfg {Array} layers
	 * Array dei layers rappresentante lo store.
	 */
	layers: null,
	
	padding: '0 5 0 5',

	/**
     * Inizializza un componente di tipo TolomeoExt.widgets.ToloLayerSelector.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	initComponent: function(config){	
		this.border = 0;
		
		this.layerStore = Ext.create('Ext.data.Store', {
		    fields: [{
		    	name: 'descrizione',
		    	mapping: 'description'
		    },{
		    	name: 'name', 
		    	mapping: 'name'
		    },{
		    	name: 'codTPN', 
		    	mapping: 'codTPN'
		    }],
		    data: this.layers
		});

		this.layerSelectorCombo = Ext.create('Ext.form.ComboBox',{
			typeAhead: true,
			forceSelection: true, 
			anchor: "-1",
			padding: '0 0 5 0',
			queryMode: 'local',
			triggerAction: 'all',
			emptyText: ToloI18n.getMsg("ToloLayerSelector.emptyText"),
			selectOnFocus: true,
			editable:false,
			fieldLabel: ToloI18n.getMsg("ToloLayerSelector.fieldLabel"),
			name: 'name',
			valueField: 'name',
			displayField: 'descrizione',
			store: this.layerStore,
		    listeners:{
		         scope: this,
		         select: function(combo, records, eOpts){
		        	 this.fireEvent("layerselected", records);
		         }
		    }
		});	
		
		this.layerFieldSet = Ext.create('Ext.form.FieldSet', {
			title: ToloI18n.getMsg("ToloLayerSelector.layerFieldSet"),
			anchor: "-1",
			autoWidth: true,
			autoHeight: true,
			items:[this.layerSelectorCombo]
		});
		
		this.callParent();
		
		this.add(this.layerFieldSet);
    }   
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets');

/**
 * Widget per la selezione della regione di interesse. Collega 
 * le specifiche funzionalità di di selezione spaziale e le 
 * relative caratteristiche in un'unica form dinamica.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.ToloSpatialSelector', {

	extend: 'Ext.Panel',
	
	padding: '0 5 0 5',
	
	/**
	 * @cfg {Object} spatialSelectorsConfig
     * Configurazione dei metodi di selezione che si vuole rendere disponibili.
     */
    spatialSelectorsConfig:{
	    /**
		 * @cfg {Object} bbox
		 * Metodo di selezione per bounding box.
		 */
        bbox:{
            xtype : 'widget.tolomeo_spatial_bbox_selector'
        },
	    /**
		 * @cfg {Object} buffer
		 * Metodo di selezione pre buffer.
		 */
        buffer:{
            xtype : 'widget.tolomeo_spatial_buffer_selector'
        },
	    /**
		 * @cfg {Object} circle
		 * Metodo di selezione per cerchio.
		 */
        circle:{
            xtype : 'widget.tolomeo_spatial_circle_selector',
            zoomToCurrentExtent : true
        },
	    /**
		 * @cfg {Object} polygon
		 * Metodo di selezione per poligono.
		 */
        polygon:{
            xtype : 'widget.tolomeo_spatial_polygon_selector'
        }
    },

	/**
	 * @cfg {String} defaultSelectionMethod
	 * (xtype) Metodo di selezione da usare come predefinito.
	 */
	defaultSelectionMethod: null,

	/**
	 * @cfg {String} filterGeometryName
	 * None del campo geometrico usato per la preparazione del filtro.
	 */
	filterGeometryName: "the_geom",

	/**
	 * @cfg {String} titleText
	 * Titolo usato per il fielset di contenimento.
	 */
	titleText: null,

	/**
	 * @cfg {String} comboEmptyText
	 * Testo predefinito per la combo box del metodo di selezione spaziale.
	 */
	comboEmptyText : null,

	/**
	 * @cfg {String} comboSelectionMethodLabel
	 * Testo per l'etichetta della combo box di selezione del metodo.
	 */
	comboSelectionMethodLabel : null,
	
	/**
	 * @property {TolomeoExt.events.ToloQueryBuilderEvtManager} qbEventManager
	 * Gestore di eventi per il query builder.
	 */
	qbEventManager: null,
    
	/**
     * Crea un nuovo TolomeoExt.widgets.ToloSpatialSelector.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	constructor : function(config) {
		this.layoutConfig = {
            xtype: 'container',
            defaults:{
                layout: "form"
            }
        };

		// Apply config
		Ext.apply(this, config);

		
		
		// initialize spatial selectors
		this.spatialSelectors = {};
		this.spatialSelectorsItems = [];
		if(this.spatialSelectorsConfig){
			for (var key in this.spatialSelectorsConfig){
				var spConfig = this.spatialSelectorsConfig[key];
				var plugin = Ext.create(spConfig.xtype, {
					qbEventManager: this.qbEventManager
				});
				this.spatialSelectors[key] = plugin;
				var selectorItem = plugin.getSelectionMethodItem();
				selectorItem.value = key;
				this.spatialSelectorsItems.push(selectorItem);
			}	
		}
		
		this.callParent(arguments);
	},

	/**
     * Inizializza un oggetto di tipo TolomeoExt.widgets.ToloSpatialSelector.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	initComponent: function(config){	
		this.border = 0;
		
		this.titleText = ToloI18n.getMsg("ToloSpatialSelector.titleText");
		this.comboEmptyText = ToloI18n.getMsg("ToloSpatialSelector.comboEmptyText");
		this.comboSelectionMethodLabel = ToloI18n.getMsg("ToloSpatialSelector.comboSelectionMethodLabel");

		
    	// prepare layout
    	var layout = {};
		Ext.apply(layout, this.layoutConfig);
		if(!layout.title){
			layout.title = this.titleText;
		}

		var selectionMethodCombo = {
			xtype : 'combo',
			// anchor : '100%',
			id : this.id + '_selectionMethod_id',
			fieldLabel : this.comboSelectionMethodLabel,
			typeAhead : true,
			triggerAction : 'all',
			lazyRender : false,
			queryMode : 'local',
			name : 'roiSelectionMethod',
			forceSelection : true,
			emptyText : this.comboEmptyText,
			allowBlank : false,
			//autoLoad : true,
			displayField : 'label',
			valueField : 'value',
			editable : false,
			readOnly : false,
			store : Ext.create('Ext.data.JsonStore', {
				autoLoad : true,
				fields : [{
					name : 'name',
					dataIndex : 'name'
				}, {
					name : 'label',
					dataIndex : 'label'
				}, {
					name : 'value',
					dataIndex : 'value'
				}],
				data : this.spatialSelectorsItems
			}),
			listeners : {
				select : function(c, record, index) {
					this._updating = true;
					this.reset();
					this._updating = false;
					var method = this.spatialSelectors[c.getValue()];//record.json.method;
					method.activate();
					this.activeMethod = method;
                    setTimeout(function(){
                        //TODO: ??? c.refOwner.doLayout();
                    }, 500);
				},
				scope : this
			}
		};

		var selItems = [];
		selItems.push(selectionMethodCombo);
		
		if(this.spatialSelectors){
	    	for (var key in this.spatialSelectors){
	    		var output = this.spatialSelectors[key];
	    		if(output){
					selItems.push(output);
	    		}
	    	}
	    }

		this.spatialFieldSet = Ext.create('Ext.form.FieldSet', {
			collapsed : true,
			checkboxToggle: true,
			title: this.titleText,
			items: selItems
		});
		
	    // initialize layout
		layout.items = [];		
		layout.items.push(this.spatialFieldSet);

    	this.items = [layout];
    	
    	this.callParent();    	
    	
    	//
    	// Update the current map extent
    	//
    	this.qbEventManager.on("mapmoved", function(extent){
    		this.currentMapExtent = extent;
    	}, this);
    },
 
	/**
     * Reimposta lo stato del selettore spaziale.
	 *
     */
    reset: function(){
    	if(this.spatialSelectors){
	    	for (var key in this.spatialSelectors){
	    		this.spatialSelectors[key].deactivate();
	    		this.activeMethod = null;
	    	}
	    	if(!this._updating 
	    		&& this.defaultSelectionMethod
	    		&& this.spatialSelectors[this.defaultSelectionMethod]){
	    		this.spatialSelectors[this.defaultSelectionMethod].activate();
				this.activeMethod = this.spatialSelectors[this.defaultSelectionMethod];
	    	}   	
    	}
    },

    setGeomFieldName: function(geomFieldName) {
    	this.filterGeometryName = geomFieldName;
    },
    
	/**
     * Genera un filtro per il metodo di selezione scelto.
     * @param {Boolean} currentExtent Stabilisce se ritornare un filtro semplice basato sull'estensione corente della mappa.
     */
	getQueryFilter: function(currentExtent){
		var currentExtentFilter = new OpenLayers.Filter.Spatial({
			type: OpenLayers.Filter.Spatial.BBOX,
			property: this.filterGeometryName,
			value: this.currentMapExtent 
		});
		
		if(currentExtent === true){
			return currentExtentFilter;
		}
		
		if(this.activeMethod && this.activeMethod.currentGeometry){
			this.activeMethod.filterGeometryName = this.filterGeometryName;
			return this.activeMethod.getQueryFilter();
		}else{
			// tornare questo se si vuole almeno il filtro sulla finestra corrente
			// return currentExtentFilter;
			return null;
		}
	},

	/**
     * Restituisce la geometria selezionata.
     * 
     */
	getGeometry: function(){
		if(this.activeMethod){
			return this.activeMethod.currentGeometry;
		}else{
			return null;
		}
	},
	
	/**
     * Restituisce l'elemento ext relativo alla combo box del metodo di selezione spaziale.
     * 
     */
	getSelectionMethodCombo: function(){		
    	var selectionMethodCombo = this.queryById(this.id + '_selectionMethod_id');
    	return  selectionMethodCombo;
	},
	
	setDecimalPrecision: function(decimalPrecision){
		for (var key in this.spatialSelectors){			
			this.spatialSelectors[key].setDecimalPrecision(decimalPrecision);			
		}	
	}
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.grid');

/**
 * Griglia Ext dinamica per gestire la visualizzazione dei risultati 
 * di una ricerca sulla base del filtro composto.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.grid.ToloFeatureGrid', {
	
	extend: 'Ext.grid.GridPanel',
	
    alias: "widget.tolomeo_featuregrid",

	/**
     * @property {Object} schema
	 * Lo schema per la griglia.
     */
	 
	/**
     * @property {Ext.form.DateField.prototype.format} dateFormat
	 * Lo schema per la griglia.
     */
	 
	/**
     * @property {Ext.form.TimeField.prototype.format} timeFormat
	 * Lo schema per la griglia.
     */

	/**
     * @cfg {String} actionTooltip
     *
     */
	actionTooltip: null,
    
	/**
     * Inizializza un nuovo TolomeoExt.widgets.grid.ToloFeatureGrid.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config){
    	
    	this.actionTooltip = ToloI18n.getMsg("ToloFeatureGrid.actionTooltip");
    	
        if (!this.dateFormat) {
            this.dateFormat = Ext.form.DateField.prototype.format;
        }
        if (!this.timeFormat) {
            this.timeFormat = Ext.form.TimeField.prototype.format;
        }
        
        if(this.store) {
            this.cm = this.createColumnModel(this.store);
        }
        
        this.callParent();
    },

	/**
     * Cancella ogni cosa creata prima di chiamare il distruttore della classe padre.
     * 
     */
    onDestroy: function() {
        TolomeoExt.widgets.grid.FeatureGrid.superclass.onDestroy.apply(this, arguments);
    },
    
	/**
     * Imposta lo store per questa griglia, riconfigurando il modello delle colonne.
     * @param {Ext.Data.Store} store Lo store da impostare.
	 * @param {Array} schema Schema opzionale per determinare i campi appropriati da mostrare per la griglia.
     */
    setStore: function(store, schema) {
        if (schema) {
            this.schema = schema;
        }
        
        if (store) {
            this.reconfigure(store, this.createColumnModel(store));
        }
    },

	/**
     * Restituisce la configurazione per il modello delle colonne.
     * @param {Ext.Data.Store} store Lo store corrente da usare.
	 * @return {Array} Il modello delle colonne
     */
    getColumns: function(store) {
//        function getRenderer(format) {
//            return function(value) {
//                //TODO When http://trac.osgeo.org/openlayers/ticket/3131
//                // is resolved, change the 5 lines below to
//                // return value.format(format);
//                var date = value;
//                if (typeof value == "string") {
//                	date = Date.parseDate(value.replace(/Z$/, ""), "c");
//                }
//                return date = date ? date.format(format) : value;
//            };
//        }
		
        var columns = [{
			xtype: 'actioncolumn',
			header: "", 
			width: 30,
			hidden: false,
			scope: this,
			items: [{
				iconCls: 'zoomaction',
				tooltip: this.actionTooltip,
				scope: this,
				handler: function(grid, rowIndex, colIndex){
					var store = grid.getStore();
					var row = store.getAt(rowIndex);
					var feature = row.data;
					if(feature){
						
						var geometry = OpenLayers.Geometry.fromWKT(feature.geometry);
						var bounds = geometry.getBounds();
						if(bounds){
							
							this.fireEvent("zoomtofeatureextent", {dataExtent: bounds});
// RESTORE THIS
//							grid.getSelectionModel().selectRow(rowIndex);					
						}
					}
				}
			}]
		}];
				
		var name, dbname, type, xtype, format, renderer;	
		
		if(this.schema){			
			var fields = this.store.model.prototype.fields;
			
			for(var i=0; i<this.schema.length; i++){
				var item = this.schema[i];
				
	            if (item) {
	                name = item.get("name");
	                dbname = item.get("dbname");
	                type = item.get("type");
	                format = null;
	                switch (type) {
	                    case "java.util.Date":
	                        format = this.dateFormat;
	                    case "java.util.Calendar":
	                        format = format ? format : this.dateFormat + " " + this.timeFormat;
	                        xtype = undefined;
	                        renderer = Ext.util.Format.dateRenderer(format) //getRenderer(format);
	                        break;
	                    case "java.lang.Boolean":
	                        xtype = "booleancolumn";
	                        break;
	                    case "java.lang.String":
	                        xtype = "gridcolumn";
	                        break;
	                    default:
	                        xtype = "numbercolumn";
	                }
	            } 
	            
                columns.push({
                    dataIndex: dbname,
                    header: name,
                    sortable: true,
                    xtype: xtype,
                    format: format,
                    renderer: xtype ? undefined : renderer
                });
			}
		}
        
        return columns;
    },

	/**
     * Invocare questo metodo per creare il modello delle colonne per la griglia.
     * @param {Ext.Data.Store} store Lo store corrente su cui creare il modello.
	 * 
     */
    createColumnModel: function(store) {
    	 this.columns = this.getColumns(store);
    	 return this.columns;
    }
    
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns("TolomeoExt.widgets.form");

/**
 * Widget per la gestione delle funzionalità relative alla modalità di selezione
 * per BBOX 
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.ToloBBOXFieldset', {
	
	extend: 'Ext.form.FieldSet',
	
    alias: "widget.tolomeo_bboxfieldset",
 
    id: "bboxFieldSet",
  
 	/**
     * @property {String} layerName.
     * Nome da usare per il layer vettoriale che rappresenta il BBOX disegnato.
     */
    layerName: "BBOX",

    /**
     * @cfg {Integer} decimalPrecision.
     * Massimo numero possibile di cifre decimali per i campi di coordinate.
     */
    decimalPrecision: 5,
    
 	/**
     * @property {String} outputSRS.
     * Codice EPSG per la trasformazione delle coordinate in 
     * visualizzazione all'interno della form.
     */
    outputSRS: 'EPSG:4326',

 	/**
     * @cfg {Object} spatialFilterOptions.
     * Opzioni di configurazione per i campi di coordinata (valori massimi e minini consentiti per i campi).
     * 
     * @example
	 *    spatialFilterOptions: {
	 *	        lonMax: 180,   
	 *	        lonMin: -180,
	 *	        latMax: 90,   
	 *	        latMin: -90  
	 *	  }
     */
    spatialFilterOptions: {
        lonMax: null,   
        lonMin: null,
        latMax: null,   
        latMin: null  
    },

    /**
     * @cfg {Boolean} displayBBOXInLayerSwitcher.
     * Usato per determinare se il layer vettoriale deve apparire all'interno del LayerSwitcher OpenLayers.
     */
    displayBBOXInLayerSwitcher: false,

    /**
     * @property {Object} defaultStyle.
     * Configurazione del OpenLayer.Style predefinito usato come stile del BBOX su mappa.
     */
	defaultStyle : {
		"strokeColor" : "#ee9900",
		"fillColor" : "#ee9900",
		"fillOpacity" : 0.4,
		"strokeWidth" : 1
	},

    /**
     * @property {Object} selectStyle.
     * Configurazione del OpenLayer.Style di selezione usato come stile del BBOX su mappa.
     */
	selectStyle : {
		"strokeColor" : "#ee9900",
		"fillColor" : "#ee9900",
		"fillOpacity" : 0.4,
		"strokeWidth" : 1
	},

    /**
     * @property {Object} temporaryStyle.
     * Configurazione del OpenLayer.Style temporaneo usato come stile del BBOX su mappa.
     */
	temporaryStyle : {
		"pointRadius" : 6,
		"fillColor" : "#FF00FF",
		"strokeColor" : "#FF00FF",
		"label" : "Select",
		"graphicZIndex" : 2
	},

 	/**
     * @property {String} northLabel.
     * Testo dell'etichetta per la coordinata Nord.
     */
    northLabel: null,
    
 	/**
     * @property {String} westLabel.
     * Testo dell'etichetta per la coordinata Ovest.
     */
    westLabel: null,
    
 	/**
     * @property {String} eastLabel.
     * Testo dell'etichetta per la coordinata Est.
     */
    eastLabel: null,
    
 	/**
     * @property {String} southLabel.
     * Testo dell'etichetta per la coordinata Sud.
     */
    southLabel: null,
    
 	/**
     * @property {String} setAoiText.
     * Testo di etichetta per il pulsante di attivazione del controllo di disegno del BOX.
     */
    setAoiText: null,
    
 	/**
     * @property {String} setAoiTooltip.
     * Testo per il tooltip del pulsante di attivazione del controllo di disegno del BOX.
     */
    setAoiTooltip: null,
    
    /**
     * @property {String} currentExtentLabel.
     * Labe del checkbox per la selezione dell'estenzione corrente della mappa
     */
    currentExtentLabel: null,
    
 	/**
     * @property {String} title.
     * Titolo del field set di contenimento.
     */
    title: null,

	/**
     * Inizializza un nuovo TolomeoExt.widgets.form.ToloBBOXFieldset.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config) {       
    	
        this.northLabel = ToloI18n.getMsg("ToloBBOXFieldset.northLabel");
        this.westLabel = ToloI18n.getMsg("ToloBBOXFieldset.westLabel");      
        this.eastLabel = ToloI18n.getMsg("ToloBBOXFieldset.eastLabel");
        this.southLabel = ToloI18n.getMsg("ToloBBOXFieldset.southLabel");
        this.setAoiText = ToloI18n.getMsg("ToloBBOXFieldset.setAoiText");
        this.setAoiTooltip = ToloI18n.getMsg("ToloBBOXFieldset.setAoiTooltip");
        this.currentExtentLabel = ToloI18n.getMsg("ToloBBOXFieldset.currentExtentLabel");
        this.title = ToloI18n.getMsg("ToloBBOXFieldset.title");
    	
    	this.addEvents(
		        /**
				 * @event
				 * Lanciato quando è stata attivata la modalità per prendere le estensioni della mappa
				 */
				"mapExtentActive",
				/**
				 * @event
				 * Lanciato quando è stata disattivata la modalità per prendere le estensioni della mappa
				 */
				"mapExtentDeactive"
		);	
    	
        this.autoHeight = true;
        this.layout = {
            type: 'table',
            // The total column count must be specified here
            columns: 3
        },
		
        this.defaults = {
            // applied to each contained panel
            bodyStyle:'padding:3px'
        };
		
        this.bodyCssClass = 'aoi-fields';
        
        // Define handlar box style
        Ext.util.CSS.createStyleSheet(".olHandlerBoxZoomBox_"+this.id+" {\n"
            +" border-width:" + 5 + "px; \n"
            +" border-style:solid; \n"
            +" border-color: " + "#66cccc" + ";"
            +" position: absolute; \n"
            +" background-color: " + "#66cccc" + "; \n"
            +" opacity: "+0.5+"; \n"
            +" font-size: 1px; \n"
            +" filter: alpha(opacity="+0.5 * 100+"); \n"
            +"}",
            "olHandlerBoxZoomBox_"+this.id);   
        
        var me = this;

        this.northField = Ext.create('Ext.form.NumberField', {
            fieldLabel: me.northLabel,
            labelAlign: "top",
            id: me.id+"_NorthBBOX",
            width: 100,
            allowBlank: false,
            decimalPrecision: me.decimalPrecision,
            allowDecimals: true,
            hideLabel : false                    
        });
        
        this.westField = Ext.create('Ext.form.NumberField', {
            fieldLabel: this.westLabel,
            labelAlign: "top",
            id: me.id+"_WestBBOX",
            width: 100,
            allowBlank: false,
            decimalPrecision: this.decimalPrecision,
            allowDecimals: true,
            hideLabel : false                    
        });
        
        this.eastField = Ext.create('Ext.form.NumberField', {
            fieldLabel: this.eastLabel,
            labelAlign: "top",
            id: me.id+"_EastBBOX",
            width: 100,
            allowBlank: false,
            decimalPrecision: this.decimalPrecision,
            allowDecimals: true,
            hideLabel : false                    
        });
              
        this.southField = Ext.create('Ext.form.NumberField', {
            fieldLabel: this.southLabel,
            labelAlign: "top",
            id: me.id+"_SouthBBOX",
            width: 100,
            allowBlank: false,
            decimalPrecision: this.decimalPrecision,
            allowDecimals: true,
            hideLabel : false                    
        });
        
        if(this.spatialFilterOptions.lonMin && this.spatialFilterOptions.lonMax){
            this.southField.minValue=this.spatialFilterOptions.lonMin;
            this.southField.maxValue=this.spatialFilterOptions.lonMax;
            this.northField.minValue=this.spatialFilterOptions.lonMin;
            this.northField.maxValue=this.spatialFilterOptions.lonMax;
        }
        
        if(this.spatialFilterOptions.latMin && this.spatialFilterOptions.latMax){
            this.eastField.minValue=this.spatialFilterOptions.latMin;
            this.eastField.maxValue=this.spatialFilterOptions.latMax;
            this.westField.minValue=this.spatialFilterOptions.latMin;
            this.westField.maxValue=this.spatialFilterOptions.latMax;
        }
        
        this.bboxButton = Ext.create('Ext.Button', {
            text: this.setAoiText,
            tooltip: this.setAoiTooltip,
            enableToggle: true,
            toggleGroup: this.toggleGroup,
            iconCls: 'aoi-button',
            height: 50,
            width: 50,
            listeners: {
                scope: this, 
                toggle: function(button, pressed) {
                    if(pressed){      
                        //
                        // Activating the new control
                        //   
                        this.selectBBOX.activate();
                    }else{
                        this.selectBBOX.deactivate();
                    }
                }
            }
        }); 
        
        this.mapExtentChkBox = Ext.create('Ext.form.Checkbox', {
        	fieldLabel: this.currentExtentLabel,
        	handler : function(cmp,checked){
        		if(checked){
        			me.fireEvent('mapExtentActive',me);
        		} else {            			
        			me.fireEvent('mapExtentDeactive',me);            			
        		}
        	}
        });
                     
        this.items = [{
        	layout: "form",
            cellCls: 'spatial-cell',            
            border: false,
            colspan: 3,
            items: [this.mapExtentChkBox,{
            	xtype: 'menuseparator'
            }]
        },{
            layout: "form",
            cellCls: 'spatial-cell',
            cls: 'center-align',
            width: 100,
            border: false,
            colspan: 3,
            items: [this.northField]
        },{
            layout: "form",
            cellCls: 'spatial-cell',
            cls: 'center-align',
            width: 100,
            border: false,
            items: [this.westField]
        },{
            layout: "form",
            cellCls: 'spatial-cell',
            cls: 'center-align',
            border: false,
            items: [this.bboxButton]                
        },{
            layout: "form",
            cellCls: 'spatial-cell',
            cls: 'center-align',
            width: 100,
            border: false,
            items: [this.eastField]
        },{
            layout: "form",
            cellCls: 'spatial-cell',
            cls: 'center-align',
            width: 100,
            border: false,
            colspan: 3,
            items: [this.southField]
        }];
            
        this.listeners = {
           "afterlayout": function(){
				if(this.ownerCt.qbEventManager){
					this.ownerCt.qbEventManager.fireEvent("afterboxlayout", {scope: me});
				}
            },
            beforecollapse : function(p) {
				if(this.ownerCt.qbEventManager){
					this.ownerCt.qbEventManager.fireEvent("removelayer", this.layerName);
				}
            }
          
        };

        this.callParent();
    },
    
	/**
     * Reimposta il pannello.
     * 
     */
    reset: function(){
		if(this.ownerCt.qbEventManager){
			this.ownerCt.qbEventManager.fireEvent("removebboxlayer", {scope: this});
		}
        this.northField.reset();
        this.southField.reset();
        this.eastField.reset();
        this.westField.reset(); 
        this.mapExtentChkBox.reset();
		this.fireEvent('unselect', this);
    },

	/**
     * Controlla la validità dei valori inserito.
     * 
     * @return {Boolean} Restituisce true se valido e false se non lo è.
     */
    isValid: function(){
        return(this.westField.isValid() &&
            this.southField.isValid() && 
            this.eastField.isValid() && 
            this.northField.isValid());
    },
    
	/**
     * Controlla se i campi della form sono sttai modificati.
     * 
     * @return {Boolean} Restituisce true se modificati e false altrimenti.
     */
    isDirty: function(){
        return(this.westField.isDirty() &&
            this.southField.isDirty() && 
            this.eastField.isDirty() && 
            this.northField.isDirty());
    },

	/**
     * Restituisce i BBOX selezionato nella proiezione configurata.
     * 
     * @return {OpenLayers.Bounds} Il Bounding Box selezionato.
     */
    getBBOXBounds: function(){
        return new OpenLayers.Bounds(
            this.westField.getValue(), 
            this.southField.getValue(), 
            this.eastField.getValue(), 
            this.northField.getValue()
        );
    },

	setDecimalPrecision: function(decimalPrecision){
		this.northField.decimalPrecision = decimalPrecision;
        this.southField.decimalPrecision = decimalPrecision;
        this.eastField.decimalPrecision = decimalPrecision;
        this.westField.decimalPrecision = decimalPrecision; 
	}
    
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.form');

/**
 * Widget per la gestione delle funzionalità relative alla modalità di selezione
 * per Buffer 
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.ToloBufferFieldset', {
	
	extend: 'Ext.form.FieldSet',
	
    alias: "widget.tolomeo_bufferfieldset",
    
    id: "bufferFieldSet",   
    
 	/**
     * @property {String} buttonIconCls.
     * Classe di stile che rappresenta l'iconaper il pulsante di selezione.
     */
    buttonIconCls:'gx-buffer',
    
    /**
     * @cfg {Number} labelWidth.
     * Larghezza delle label
     */
    labelWidth: 70,
    
    /**
     * @cfg {Number} fieldWidth.
     * Larghezza dei campi
     */
    fieldWidth : 100,

    /**
     * @cfg {String} bufferFieldLabel.
     * Testo per la label del campo numerico del buffer.
     */
	bufferFieldLabel: null,
	
    /**
     * @cfg {String} bufferFieldSetTitle.
     * Testo per il titolo del field set del buffer.
     */
	bufferFieldSetTitle: null,

    /**
     * @cfg {String} coordinatePickerLabel.
     * Testo per l'etichetta del coordinate picker.
     */
	coordinatePickerLabel: null,
	
    /**
     * @cfg {String} draweBufferTooltip.
     * Testo del il tooltip per il bottone di disegno del buffer.
     */
	draweBufferTooltip: null,
	
 	/**
     * @property {String} outputSRS.
     * Codice EPSG per la trasformazione delle coordinate in 
     * visualizzazione all'interno della form.
     */
	outputSRS: "EPSG:4326",
	
    /**
     * @cfg {String} selectLayerName.
     * Nome del layer vettoriale che rappresenta il buffer su mappa.
     */
	selectLayerName: "buffer-layer",
	
    /**
     * @cfg {Boolean} displayInLayerSwitcher.
     * Usato per determinare se il layer vettoriale deve apparire all'interno del LayerSwitcher OpenLayers.
     */
	displayInLayerSwitcher: false,
	
    /**
     * @property {Object} selectStyle.
     * Configurazione del OpenLayer.Style usato come stile del punto su mappa.
     */
	selectStyle: {
		strokeColor: "#FF0000",
		handlerFillColor: "#FFFFFF",
		fillColor: "#FFFFFF",
		fillOpacity: 0,
		strokeWidth: 2
	},
	
    /**
     * @cfg {Integer} minValue.
     * valore minimo per il raggio del buffer.
     */
	minValue: 1,

    /**
     * @cfg {Integer} maxValue.
     * valore massimo per il raggio del buffer.
     */
	maxValue: 5000,
	
    /**
     * @cfg {Integer} decimalPrecision.
     * Massimo numero possibile di cifre decimali per i campi di coordinate.
     */
	decimalPrecision: 0,
	
    /**
     * @cfg {Boolean} geodesic.
     * 
     */
	geodesic: false,
	
    /**
     * @cfg {Object} config.
     * 
     */
	config: {
	    /**
	     * @cfg {OpenLayer.Layer.Vector} bufferLayer.
	     * 
	     */
        bufferLayer: null
	},
	
	/**
     * Inizializza un nuovo TolomeoExt.widgets.form.ToloBufferFieldset.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config) {
    	
    	this.bufferFieldLabel = ToloI18n.getMsg("ToloBufferFieldset.bufferFieldLabel");
    	this.bufferFieldSetTitle = ToloI18n.getMsg("ToloBufferFieldset.bufferFieldSetTitle");
    	this.coordinatePickerLabel = ToloI18n.getMsg("ToloBufferFieldset.coordinatePickerLabel");
    	this.draweBufferTooltip = ToloI18n.getMsg("ToloBufferFieldset.draweBufferTooltip");

    	// per adesso lo impongo a prescindere, poi vediamo.
    	this.distanceUnit = 'm';
    	this.bufferFieldLabel += " [" + this.distanceUnit + "]"; 
    	
		this.coordinatePicker = Ext.create('TolomeoExt.widgets.form.ToloCoordinatePicker', {
			labelWidth: this.labelWidth,
			fieldWidth: this.fieldWidth,
			fieldLabel: this.coordinatePickerLabel,
			//fieldBodyCls : 'prova',
			latitudeEmptyText: this.latitudeEmptyText,
			longitudeEmptyText: this.longitudeEmptyText,
			outputSRS: this.outputSRS,
			toggleGroup: this.toggleGroup,
			listeners: {
				scope: this,

                afterrender: function(me) {
                    me.labelCell.applyStyles('vertical-align: middle');
                },

				updatebuffer: function(lonlat, scope){
				    var cv = this.coordinatePicker.isValid();
				    var bv = this.bufferField.isValid();
					if(cv && bv ){                                 
                        var coords = this.coordinatePicker.getCoordinate();
                        var lonlat = new OpenLayers.LonLat(coords[0], coords[1]);
                        var point = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
                        
        				if(this.qbEventManager){
        					this.qbEventManager.fireEvent("drawbuffer", 
        							point, 
        							this.geodesic, 
        							this.bufferField.getValue(), 
        							this.selectStyle,
        							this.selectLayerName,
        							this.displayInLayerSwitcher,
        							this.setBufferLayer, 
        							this);
        				}
                    }
				},
				reset: function(selectLayerName){
					if(this.qbEventManager){
						this.qbEventManager.fireEvent("removelayer", selectLayerName);
					}
				},
				update: function(lonlat, scope){
					if(this.qbEventManager){
						this.qbEventManager.fireEvent("updatemappoint", lonlat, scope);
					}
				}
			}			
		});
		
		this.bufferField = Ext.create('Ext.form.NumberField', {
			name: 'buffer',
			ref: 'bufferField',
			padding: '10 0 10 0',
			fieldLabel: this.bufferFieldLabel,
			labelWidth: this.labelWidth,
			allowBlank: false,
			disabled: false,
			width: (this.labelWidth + this.fieldWidth + 5), // 5 is default labelPad
			minValue: this.minValue,
            maxValue: this.maxValue,
			enableKeyEvents: true,
		    decimalPrecision: this.decimalPrecision,
			allowDecimals: true,
			hideLabel : false,
			validationDelay: 1500
		});
		
		this.bufferField.addListener("change", function(){   
			if(this.coordinatePicker.isValid() && this.bufferField.isValid()){						
				var coords = this.coordinatePicker.getCoordinate();
				var lonlat = new OpenLayers.LonLat(coords[0], coords[1]);
				var point = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);								
				
				if(this.qbEventManager){
					this.qbEventManager.fireEvent("drawbuffer", 
							point, 
							this.geodesic, 
							this.bufferField.getValue(), 
							this.selectStyle,
							this.selectLayerName,
							this.displayInLayerSwitcher,
							this.setBufferLayer,
							this);
				}
			}else{
				this.resetBuffer();
			}
		}, this, {delay: 500});
		
		this.items = [
			this.coordinatePicker,
			{
			    xtype: 'menuseparator'
			  },
			this.bufferField
		];
        
		this.title = this.bufferFieldSetTitle;		
		this.callParent();			
    },
	
	/**
     * Reimposta il buffer tramite un evento gestito dal Manager.
     * 
     */
	resetBuffer: function(){
		if(this.qbEventManager){
			this.qbEventManager.fireEvent("removelayer", this.selectLayerName);
		}
	},
	
	/**
     * Controlla la validità del valore inserito.
     * 
     * @return {Boolean} Restituisce true se valido e false se non lo è.
     */
	isValid: function(){
		return(this.coordinatePicker.isValid() &&
			this.bufferField.isValid());
	},
	
	/**
     * Avvia la procedura di reimpostazione del buffer.
     * 
     */	
	resetPointSelection: function(){
		this.coordinatePicker.resetPoint();
        this.bufferField.reset();
		this.resetBuffer();
	},
	
	/**
     * Imposta il layer OpenLayers per il buffer.
     * @param {OpenLayers.Layer.Vector} bufferLayer Il layer vettoriale OpenLayers che rappresenta il buffer.
     * @param {OpenLayers.Feature.Vector} bufferFeature La feature vettoriale da disegnare du mappa.
     */
	setBufferLayer: function(bufferLayer, bufferFeature){
		this.bufferLayer = bufferLayer;
		this.fireEvent('bufferadded', this, bufferFeature);
	},
	
	setDecimalPrecision: function(decimalPrecision){
		this.coordinatePicker.setDecimalPrecision(decimalPrecision);
	}
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.form');

/**
 * Una combo box Ext per selezionare gli operatori di comparazione disponibili 
 * per i filtri OGC.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.ToloComparisonComboBox', {
	
	extend: 'Ext.form.ComboBox',
	
	alias: 'widget.tolomeo_comparisoncombo',
    
	displayTpl:'<tpl for=".">{[values.text]}</tpl>',
	
	listConfig: {
		 
        // Custom rendering template for each item
        getInnerTpl: function() {                	        
        	// return '{[(values.tipTitle || values.tipText)  ? values.text + " <div data-qtitle=\\"" + values.tipTitle + "\\"  data-qtip=\\"" + values.tipText + "\\" style=\\"color:gray; border-bottom: dashed 1px gray; border-top: dashed 1px gray; \\">" + values.tipText + "</div>" : values.text]}';
        	return '{[(values.tipTitle || values.tipText)  ? " <div data-qtitle=\\"" + values.tipTitle + "\\"  data-qtip=\\"" + values.tipText + "\\" >" + values.text + "</div>" : values.text]}';
        }
	},
	
 	/**
     * @property {Array} allowedTypes.
     * Tipi di operatori disponibili.
     */
    allowedTypes: null,

 	/**
     * @cfg {Boolean} allowBlank.
     * Stabilisce se consentire testo vuoto all'interno della combo.
     */
    allowBlank: false,

 	/**
     * @cfg {String} mode.
     * Stabilisce il metodo di caricamento dello store.
     */
    mode: "local",

 	/**
     * @cfg {Boolean} typeAhead.
     * 
     */
    typeAhead: true,

 	/**
     * @cfg {Boolean} forceSelection.
     * 
     */
    forceSelection: true,

 	/**
     * @cfg {String} triggerAction.
     * 
     */
    triggerAction: "all",

 	/**
     * @cfg {Integer} width.
     * 
     */
    width: 80,

 	/**
     * @cfg {Boolean} editable.
     * 
     */
    editable: true,
    
    /**
     * @cfg {String} editable.
     * To make sure the filter in the store is not cleared the first time the ComboBox trigger is used don't change
     */
    lastQuery: '',
  
	/**
     * Inizializza un nuovo TolomeoExt.widgets.form.ToloComparisonComboBox.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config) {
    	
    	this.allowedTypes = [
            [OpenLayers.Filter.Comparison.EQUAL_TO, "=", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.uguale.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.uguale.tiptext")],
            [OpenLayers.Filter.Comparison.NOT_EQUAL_TO, "<>", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.diverso.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.diverso.tiptext")],
            [OpenLayers.Filter.Comparison.LESS_THAN, "<", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.minore.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.minore.tiptext")],
            [OpenLayers.Filter.Comparison.GREATER_THAN, ">", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.maggiore.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.maggiore.tiptext")],
            [OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, "<=", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.minug.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.minug.tiptext")],
            [OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, ">=", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.magug.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.magug.tiptext")],
            [OpenLayers.Filter.Comparison.LIKE, "like", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.like.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.like.tiptext")],
            // simulate ilike operator (not match case)
            ["ilike", "ilike", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.ilike.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.ilike.tiptext")],
            [OpenLayers.Filter.Comparison.BETWEEN, "between", ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.between.tiptitle"), ToloI18n.getMsg("ToloComparisonComboBox.allowedTypes.between.tiptext")]
        ];

    	
        var defConfig = {
            displayField: "text",
            valueField: "value",
            store: new Ext.data.SimpleStore({
                data: this.allowedTypes,
                fields: ["value", "text", "tipTitle", "tipText"]
            }),
            value: (this.value === undefined) ? this.allowedTypes[0][0] : this.value,
            listeners: {
                // workaround for select event not being fired when tab is hit
                // after field was autocompleted with forceSelection
                "blur": function() {
                    var index = this.store.findExact("value", this.getValue());
                    if (index != -1) {
                        this.fireEvent("select", this, this.store.getAt(index));
                    } else if (this.startValue != null) {
                        this.setValue(this.startValue);
                    }
                }
            }
        };
        
        Ext.applyIf(this, defConfig);
        
        this.callParent();
        
    }

});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.form');

/**
 * Widget relativa al Form Container per la gestione del campo di selezione 
 * delle coordinate puntuali su mappa. 
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.ToloCoordinatePicker', {
	
	extend: 'Ext.form.FieldContainer',

    alias: 'tolomeo_coordinate_picker',
	
	/**
     * @property {String} fieldLabel.
     *
     */
    fieldLabel: null,
	
    /**
     * @cfg {Number} fieldWidth.
     * Larghezza dei campi
     */
    fieldWidth : 100,
    
	/**
     * @property {String} pointSelectionButtionTip.
     *
     */
    pointSelectionButtionTip: null,
	
	/**
     * @property {String} latitudeEmptyText.
     * Stringa da mostrare per componente non valorizzato (latitudine)
     */
    latitudeEmptyText: null,
	 
 	/**
      * @property {String} longitudeEmptyText.
      * Stringa da mostrare per componente non valorizzato (longitudine)
      */
    longitudeEmptyText: null,
	 
 	/**
     * @property {String} outputSRS.
     * Codice EPSG per la trasformazione delle coordinate in 
     * visualizzazione all'interno della form.
     */
    outputSRS: 'EPSG:4326',
    
 	/**
     * @property {String} buttonIconCls.
     * Classe di stile usata per l'icona del pulsante di selezione.
     */
    buttonIconCls:'gx-cursor',

    /**
     * @property {Object} selectStyle.
     * Configurazione del OpenLayer.Style usato come stile del punto su mappa.
     */
    selectStyle:{
        pointRadius: 4,
        graphicName: "cross",
        fillColor: "#FFFFFF",
        strokeColor: "#FF0000",
        fillOpacity:0.5,
        strokeWidth:2
    },

    /**
     * @property {Object} defaultSelectStyle.
     * Configurazione del OpenLayer.Style usato per riempire i campi mancati di "selectStyle".
     */
    defaultSelectStyle:{
        pointRadius: 4, // sized according to type attribute
        graphicName: "cross",
        fillColor: "#0000FF",
        strokeColor: "#0000FF",
        fillOpacity:0.5,
        strokeWidth:2        
    },
	
    /**
     * @cfg {Integer} decimalPrecision.
     * Massimo numero possibile di cifre decimali per i campi di coordinate.
     */
    decimalPrecision: 10,
    
    /**
     * @cfg {String} selectLayerName.
     * Nome del layer vettoriale che rappresenta il punto su mappa.
     */
    selectLayerName: "select_marker_position_layer",
    
    /**
     * @cfg {Boolean} displayInLayerSwitcher.
     * Usato per determinare se il layer vettoriale deve apparire all'interno del LayerSwitcher OpenLayers.
     */
    displayInLayerSwitcher: false,
    
	/**
     * Inizializza un nuovo TolomeoExt.widgets.form.ToloCoordinatePicker.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent:function(config){
    	/*
        this.layout = {
            type: 'hbox'
        };
        */
    	
    	this.fieldLabel = ToloI18n.getMsg("ToloCoordinatePicker.fieldLabel");
        this.pointSelectionButtionTip = ToloI18n.getMsg("ToloCoordinatePicker.pointSelectionButtionTip");
        this.latitudeEmptyText = ToloI18n.getMsg("ToloCoordinatePicker.latitudeEmptyText");
        this.longitudeEmptyText = ToloI18n.getMsg("ToloCoordinatePicker.longitudeEmptyText");

    	
        this.layout = {
                type: 'table',
                // The total column count must be specified here
                columns: 2
            };
        
        this.defaults = {
            // applied to each contained panel
            bodyStyle:'padding:0px;'
        };
		
        var compositeField = this;
		
		Ext.applyIf(this.selectStyle, this.defaultSelectStyle);
	
		this.items= [{
            layout: "form",
            cellCls: 'spatial-cell',
            cls: 'center-align',
            width: this.fieldWidth,
            border: false,            
            items: [{
                xtype     : 'numberfield',
                emptyText : this.longitudeEmptyText,	
                ref:'longitudeField',
                decimalPrecision:this.decimalPrecision,
                allowBlank: false,
                name: 'lon',
				listeners: {
					scope:this,
					change: this.updatePoint
				}
            }]
        },{
            layout: "form",
            cellCls: 'spatial-cell',
            cls: 'center-align',            
            rowspan: 2,
            border: false,
            bodyStyle:'padding:10px;',
            items: [{
                layout: "form",
                cellCls: 'spatial-cell',
                cls: 'center-align',
                border: false,
                items: [{
                    xtype: 'button',
    				ref:'clickToggle',
                    tooltip: this.pointSelectionButtionTip,
                    iconCls: this.buttonIconCls,
                    enableToggle: true,
                    toggleGroup: this.toggleGroup,
                    scale: 'large',
                    width: 40,
                    height: 40,
                    listeners: {
                      scope: this, 
                      toggle: function(button, pressed) {  
                         if(pressed){
                              this.selectLonLat.activate();
                          }else{
                              this.selectLonLat.deactivate();
                          }
                      }
                    }
                }]                
            }]
        },{
            layout: "form",
            cellCls: 'spatial-cell',
            cls: 'center-align',
            width: this.fieldWidth,
            border: false,
            items: [ {
                xtype     : 'numberfield',
                emptyText : this.latitudeEmptyText,
                ref: 'latitudeField',
                decimalPrecision: this.decimalPrecision,
                allowBlank:false,
                name: 'lat',
				listeners: {
					scope:this,
					change: this.updatePoint
				}
            }]
        }];
        this.callParent(arguments);
        
        this.on("added", function(scope){
        	scope.latitudeField = scope.query('numberfield[ref=latitudeField]')[0];
        	scope.longitudeField = scope.query('numberfield[ref=longitudeField]')[0];
        	scope.clickToggle = scope.query('button[ref=clickToggle]')[0];
        	scope.updateStep();
        });                
    },
    
	/**
     * Controlla la validità dei valori inseriti.
     * 
     * @return {Boolean} Restituisce true se valido e false se non lo è.
     */
    isValid: function(){
    	if(this.latitudeField.isValid() &&
    	    	this.longitudeField.isValid()){
    		return true;
    	}else{
    		return false;
    	}
    },
	
	/**
     * Prende i valori dai campi e avvia la procedura di disegno sulla mappa.
     * 
     */
    updatePoint: function(){
        var lat = this.latitudeField.getValue();
		var lon = this.longitudeField.getValue();
		if( lon && lat ){
			//add point
			var lonlat = new OpenLayers.LonLat(lon,lat);
			
			 /*  DECOMMENTARE SE SI VUOLE visualizzare le coordinate nel sistema di riferimento impostato per il buffer selector
            
	            var tPoint = new Point(lonlat.lon, lonlat.lat);
	            tPoint.transform(this.outputSRS,this.projectionObject.getCode());
	            
	            lonlat.lon = tPoint.x;
	            lonlat.lat = tPoint.y;
	        */						
			
			this.updateMapPoint(lonlat);
		}
    },
	
	/**
     * Lancia l'evento per la rimozione del layer vettoriale 
     * che rappresente la selezione del punto sulla mappa.
     * 
     */
    resetMapPoint:function(){
    	this.fireEvent("reset", this.selectLayerName);
    },

	/**
     * Reimposta i campi della form e rimuove il layer dalla mappa.
     *
     */
    resetPoint:function(){
		this.latitudeField.reset();
        this.longitudeField.reset();
		
        this.resetMapPoint();
	},

	/**
     * Usato per impostare la pressione del pulsante di attivazione 
     * del controllo di disegno.
     * @param {Boolean} toggle valore del toggle da impostare per il componente Ext.
     */
	toggleButton: function(toggle){
		this.clickToggle.toggle(toggle);
	},
	
	/**
     * Aggiorna il punto sulla mappa tramite eventi gestiti dal Manager a livello superiore.
     * del controllo di disegno.
     * @param {OpenLayers.LonLat} lonlat valore delle coordinate da usare per il punto su mappa.
     */
    updateMapPoint:function(lonlat){
        if(this.selectStyle){
        	this.resetMapPoint();
        	this.fireEvent("update", lonlat, this);
        	this.fireEvent("updatebuffer", lonlat, this);
        }    
    },
	 
	/**
     * Recupera le coordinate dai campi della form.
     * del controllo di disegno.
     * @return {Array} Array delle coordinate.
     */
	getCoordinate: function(){
		return [this.longitudeField.getValue(), this.latitudeField.getValue()];
	},
	
	setDecimalPrecision: function(decimalPrecision){
		this.decimalPrecision = decimalPrecision;
		this.latitudeField.decimalPrecision = decimalPrecision;
    	this.longitudeField.decimalPrecision = decimalPrecision;
    	this.updateStep();
	},
	
	updateStep: function(){
		var step = 1/Math.pow(10,this.decimalPrecision-2);
		this.latitudeField.step  = step;
    	this.longitudeField.step = step;
	}
    
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.form');

/**
 * Un campo Form che rappresenta un filtro di comparazione
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.ToloFilterField', {
	
	extend: 'Ext.form.FieldContainer',
	
	alias: 'widget.tolomeo_tolofilterfield',
	    
	/**
     * @cfg {String} lowerBoundaryTip
     * Tooltip per il campo inferiore di valorizzazione.
     *
     */
    lowerBoundaryTip: null,
     
	/**
     * @cfg {String} upperBoundaryTip
     * Tooltip per il campo superiore di valorizzazione.
     *
     */
    upperBoundaryTip: null,
    
	/**
     * @cfg {String} invalidRegExText
     * Testo mostrato in caso di valore campo non valido.
     *
     */
    invalidRegExText: null,
     
	/**
     * @cfg {Boolean} caseInsensitiveMatch [caseInsensitiveMatch="false"]
	 * Il filtro di comparazione per i campi di tipo stringa deve essere case insensitive ?
     */
    caseInsensitiveMatch: false,

	/**
     * @property {OpenLayers.Filter} filter
	 * Filtro non logico opzionale messo a disposizione nella configurazione iniziale. Per 
	 * recuperare il filtro usare il metodo ''getFilter'' invece di accedere direttamente questa 
	 * proprietà.
     */
    filter: null,
    
	/**
     * @property {Ext.DataStore} attributes
	 * Rappresenta lo store configurato degli attributi del layer 
	 * da usare all'interno della combo box di filtraggio delle proprietà.
     */
    attributes: null,

	/**
     * @property {Object} comparisonComboConfig
	 * Oggetto di configurazione per la combo box di comparazione.
     */

	/**
     * @property {Object} attributesComboConfig
	 * Oggetto di configurazione per la combo box degli attributi.
     */
    attributesComboConfig: null,
    
	/**
     * @cfg {Boolean} autoComplete [autoComplete="false"]
	 * Abilita la funzionalità di autocompletamento per i campi stringa.
     */
    autoComplete: false,
    
	/**
     * @cfg {Object} autoCompleteCfg [autoCompleteCfg="{}"]
	 * Stabilisce la configurazione da usare per la funzionalità di autocompletamento.
	 *
	 * @example
	 * autoCompleteCfg: {
	 *  	url: 'http://localhost:8080/tolomeobinj/UniqueValueServlet',
	 *		pageSize: 10
	 * }
     */
    autoCompleteCfg: {},
    
	/**
     * @cfg {Integer} pageSize [autoComplete="5"]
	 * Configura il numero massimo predefinito di elementi per pagina per la 
	 * combo box di autocompletamento.
     */
    pageSize: 5,
    
	/**
     * Inizializza un nuovo TolomeoExt.widgets.form.ToloFilterField.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config) {
    	
        this.lowerBoundaryTip = ToloI18n.getMsg("ToloFilterField.lowerBoundaryTip");
        this.upperBoundaryTip = ToloI18n.getMsg("ToloFilterField.upperBoundaryTip");
        this.invalidRegExText = ToloI18n.getMsg("ToloFilterField.invalidRegExText");
    	
        var me = this;
        
        this.combineErrors = false;
        
        if (!this.dateFormat) {
            this.dateFormat = Ext.form.DateField.prototype.format;
        }
        if (!this.timeFormat) {
            this.timeFormat = Ext.form.TimeField.prototype.format;
        }        
        if(!this.filter) {
            this.filter = this.createDefaultFilter();
        }
        
        var mode = "local";
        var attributes = this.attributes;
        
        this.createDefaultConfigs();
        
        var defAttributesComboConfig = {
            xtype: "combo",
            store: attributes,
            editable: false,
            typeAhead: true,
            forceSelection: true,
            queryMode: mode,
            triggerAction: "all",
            ref: "property",
            allowBlank: this.allowBlank,
            displayField: "name",
            valueField: "dbname",
            value: this.filter.property,
            listeners: {
                select: function(combo, records) {
                	var record = records;
                	if(records instanceof Array){
                		record = records[0];
                	}
                	
                    this.filter.property = record.get("dbname");
                    this.fieldType = record.get("type");
                    this.fieldRegEx = record.get("regex");
                    this.layerCodeTPN = record.get("codTPN");
                    this.attributeLogicalName = record.get("attributeLogicalName");
                    
                    // ////////////////////////////////////////////////////////////////
                    // Check if the autocomplete must be disabled for the single field
                    // ////////////////////////////////////////////////////////////////
                    var autocomplete = record.get("autocomplete");
                    this.autoCompleteFieldCheck = autocomplete.active != undefined ? 
                    		autocomplete.active && this.autoComplete : this.autoComplete;
                    
                    if(this.autoCompleteFieldCheck){
                    	var mode = autocomplete.mode || "remote";
                    	Ext.copyTo(this.autoCompleteCfg, {
                    		 autoCompleteMode: mode,
                    		 minChars: mode == "remote" ? autocomplete.minChars || 1 : 1
                    	}, ["autoCompleteMode", "minChars"]);
                    	
                        //
                        // Update the this.autoCompleteDefault config with minChars retrieved by the server
                        //
                        this.autoCompleteDefault["single"].minChars = this.autoCompleteCfg.minChars;
                        this.autoCompleteDefault["lower"].minChars = this.autoCompleteCfg.minChars;
                        this.autoCompleteDefault["upper"].minChars = this.autoCompleteCfg.minChars;
                        
                        this.autoCompleteDefault["single"].pageSize = mode == "remote" ? 
                        		this.autoCompleteCfg.pageSize || this.pageSize : 0;
                        this.autoCompleteDefault["lower"].pageSize = mode == "remote" ? 
                        		this.autoCompleteCfg.pageSize || this.pageSize : 0; 
                        this.autoCompleteDefault["upper"].pageSize = mode == "remote" ? 
                        		this.autoCompleteCfg.pageSize || this.pageSize : 0;
                    }
                    
                    if(!this.comparisonCombo) {
                        this.comparisonCombo = this.items.get(1);
                    }
                    
                    this.comparisonCombo.enable();
                    this.comparisonCombo.reset();
                    
                    if(!this.valueWidgets) {
                        this.valueWidgets = this.items.get(2);
                    }
                    this.valueWidgets.removeAll();
                    
                    this.setFilterType(null);
        
                    this.doLayout();
                    this.fireEvent("change", this.filter, this);
                },
                // workaround for select event not being fired when tab is hit
                // after field was autocompleted with forceSelection
                "blur": function(combo) {
                    var index = combo.store.findExact("dbname", combo.getValue());
                    if (index != -1) {
                        combo.fireEvent("select", combo, combo.store.getAt(index));
                    } else if (combo.startValue != null) {
                        combo.setValue(combo.startValue);
                    }
                },
                scope: this
            },            
            width: 200
        };
        
        var defComparisonComboConfig = {
            xtype: "tolomeo_comparisoncombo",
            ref: "type",
            disabled: true,
            editable: false,
            allowBlank: this.allowBlank,
            value: this.filter.type,
            listeners: {
                select: function(combo, records) {        
                	var record = records;
                	if(records instanceof Array){
                		record = records[0];
                	}
                    this.createValueWidgets(record.get("value"));
                },
                expand: function(combo) {
                    var store = combo.getStore();
                    store.clearFilter();
                    if(this.fieldType === "java.util.Date" || 
                    		this.fieldType === "java.util.Calendar" || 
                    		this.fieldType === "'java.math.BigInteger" || 
                    		this.fieldType === "java.lang.Double" || 
                    		this.fieldType === "java.math.BigDecimal" || 
                    		this.fieldType === "java.lang.Integer" || 
                    		this.fieldType === "java.lang.Long" || 
                    		this.fieldType === "java.lang.Float" || 
                    		this.fieldType === "java.lang.Short" ||
                    		this.fieldType === "java.lang.Number"){
                        store.filter([
                          {
                            fn   : function(record) {
                                return (record.get('text') != "like") && (record.get('text') != "ilike");
                            },
                            scope: this
                          }                      
                        ]);
                    }else if(this.fieldType === "java.lang.Boolean"){
                        store.filter([
                          {
                            fn   : function(record) {
                                return (record.get('name') == "=");
                            },
                            scope: this
                          }                      
                        ]);
                    }else if(this.fieldType === "java.lang.String"){
                        store.filter([
                          {
                            fn   : function(record) {
                            	return (record.get('text') != "between");
                            },
                            scope: this
                          }                      
                        ]);
                    }  
                },
                scope: this
            },            
            width: 200        
        };
        
        this.attributesComboConfig = this.attributesComboConfig || {};
        Ext.applyIf(this.attributesComboConfig, defAttributesComboConfig);
        
        this.comparisonComboConfig = this.comparisonComboConfig || {};        
        Ext.applyIf(this.comparisonComboConfig, defComparisonComboConfig);

        this.items = [this.attributesComboConfig, this.comparisonComboConfig, {
            xtype: 'container',
            isFormField: true,
            isValid: function() { return true; },
            reset: function() {
                 this.eachItem(function(a) {
                    a.reset()
                });
            },
            eachItem: function(b, a) {
                if (this.items && this.items.each) {
                    this.items.each(b, a || this)
                }
            },
            layout  : 'hbox',            
            defaultMargins: '0 3 0 0',
            width: 200
        }];
        
        this.addEvents(
			/**
			 * @event 
			 * Lanciato a seguito di un cambiamento del valore del componente.
			 */
            "change"
        ); 

        this.callParent();
    },
    
	/**
     * Crea e aggiunge alla form una combo box di auto completamento.
     * @param {Object} config Un opzionale oggetto di configurazione per il componente ExtJs.
     * @return {Object} Ritorna l'oggetto relativo alla combobox di auto completamento.
     */
    addAutocompleteStore: function(config) {
        var uniqueValuesStore = new TolomeoExt.data.ToloUniqueValuesStore({
            pageSize: this.autoCompleteCfg.autoCompleteMode == "remote" ? this.autoCompleteCfg.pageSize || this.pageSize : 0,
			TOLOMEOServer: this.TOLOMEOServer,
			TOLOMEOContext: this.TOLOMEOContext
        });
        
        this.initUniqueValuesStore(uniqueValuesStore, this.layerCodeTPN, this.filter.property,this.attributeLogicalName);
        
        return Ext.apply(Ext.apply({}, config), {store: uniqueValuesStore});
    },
    
	/**
     * Se lo store degli attributi contiene anche una RegEx di validazione, applica 
     * il validatore al componente Ext che rappresenta il valore.
     * 
     * @param {String} type Tipo dell'attributo relativo per configurare il componente.
     * @return {Object} Ritorna la configurazione relativa alla campo valore della proprietà.
     */
    createValueWidget: function(type) {
        if(this.autoComplete && this.autoCompleteFieldCheck && this.fieldType === 'java.lang.String') {
            return Ext.apply({}, this.addAutocompleteStore(this.autoCompleteDefault[type]));
        } else {
        	var config = {};
        	if(this.fieldRegEx){
        		var me = this;
        		var valueTest = new RegExp(this.fieldRegEx);
        		config = Ext.apply(config, {
                    validator: function(value) {
                        return valueTest.test(value) ? true : me.invalidRegExText;
                    }
        		});
        	}
        	
            return Ext.apply(config, this.fieldDefault[type][this.fieldType]);
        }
    },
    
	/**
     * Crea il componente Ext destinato a contenere il valore delle proprietà.
     * @param {String} type Tipo dell'attributo relativo per configurare il componente.
     * 
     */
    createValueWidgets: function(type) {
        if((type !== this.filter.type) || (this.filter.type == OpenLayers.Filter.Comparison.LIKE)) {
        	
            this.setFilterType(type);
            
            if(!this.valueWidgets) {
                this.valueWidgets = this.items.get(2);
            }
            this.valueWidgets.removeAll();
            if (type === OpenLayers.Filter.Comparison.BETWEEN) {
                this.valueWidgets.add(this.createValueWidget('lower'));
                this.valueWidgets.add(this.createValueWidget('upper'));
            } else {
            	var vw = this.createValueWidget('single');
            	vw.width = vw.maxWidth;    
            	/*
            	if (type === OpenLayers.Filter.Comparison.LIKE || type === 'ilike') {
            		vw.emptyText = this.wildCardText
            	} 
            	*/           	               
                this.valueWidgets.add(vw);
            }
            
            this.doLayout();
            
            this.fireEvent("change", this.filter, this);
        }
    },
    
	/**
     * Imposta la configurazione predefinita per la gestione dinamica dei componenti.
     * 
     */
    createDefaultConfigs: function() {
        this.defaultItemsProp = {
            'single': {
                validateOnBlur: false,
                ref: "value",
                // grow: true,
                // growMin: 80,
                width: 80,
                anchor: "100%",
                allowBlank: this.allowBlank,
                listeners: {
                    "change": function(field, value) {
                        this.filter.value = value;
                        this.fireEvent("change", this.filter, this);
                    },
                    "blur": function(field){
                    
                    },
                    scope: this
                }   
            },
            
           'lower': {
                // grow: true,
                // growMin: 80,
                width: 80,
                ref: "lowerBoundary",
                anchor: "100%",
                allowBlank: this.allowBlank,
                listeners: {
                    "change": function(field, value) {
                        this.filter.lowerBoundary = value;
                        this.fireEvent("change", this.filter, this);
                    },
                    "autosize": function(field, width) {
                        field.setWidth(width);
                        field.ownerCt.doLayout();
                    },
                    scope: this
                }
            },
            
            'upper': {
                // grow: true,
                // growMin: 80,
                width: 80,
                ref: "upperBoundary",
                allowBlank: this.allowBlank,
                listeners: {
                    "change": function(field, value) {
                        this.filter.upperBoundary = value;
                        this.fireEvent("change", this.filter, this);
                    },

                    scope: this
                }
            }
        };
        
        this.fieldDefault = {};
        
        var maxFieldWidth = 200; // 70 - 80
        var numberFieldWidth = maxFieldWidth/2; 
        for(key in this.defaultItemsProp) {
            this.fieldDefault[key] = {
                'java.lang.String': Ext.applyIf({
                    xtype: "textfield",
                    width: maxFieldWidth,
                    maxWidth: maxFieldWidth
                }, this.defaultItemsProp[key]),
                'java.lang.Double': Ext.applyIf({
                    xtype: "numberfield",
                    allowDecimals:true,
                    decimalPrecision: 10,
                    width: numberFieldWidth,
                    maxWidth: maxFieldWidth
                },this.defaultItemsProp[key]),
                'java.lang.Float': Ext.applyIf({
                    xtype: "numberfield",
                    allowDecimals:true,
                    decimalPrecision: 10,
                    width: numberFieldWidth,
                    maxWidth: maxFieldWidth
                },this.defaultItemsProp[key]),
                'java.math.BigDecimal': Ext.applyIf({
                    xtype: "numberfield",
                    allowDecimals:true,
                    decimalPrecision: 10,
                    width: numberFieldWidth,
                    maxWidth: maxFieldWidth
                },this.defaultItemsProp[key]),
                'java.math.BigInteger': Ext.applyIf({
                    xtype: "numberfield",
                    allowDecimals:false,
                    width: numberFieldWidth,
                    maxWidth: maxFieldWidth
                },this.defaultItemsProp[key]),
                'java.lang.Integer': Ext.applyIf({
                    xtype: "numberfield",
                    allowDecimals:false,
                    width: numberFieldWidth,
                    maxWidth: maxFieldWidth
                },this.defaultItemsProp[key]),
                'java.lang.Long': Ext.applyIf({
                    xtype: "numberfield",
                    allowDecimals:false,
                    width: numberFieldWidth
                },this.defaultItemsProp[key]),
                'java.lang.Short': Ext.applyIf({
                    xtype: "numberfield",
                    allowDecimals:false,
                    width: numberFieldWidth,
                    maxWidth: maxFieldWidth
                },this.defaultItemsProp[key]),
                'java.util.Date': Ext.applyIf({
                    xtype: "datefield",
                    width: numberFieldWidth,
                    maxWidth: maxFieldWidth,
                    allowBlank: false,
                    format: this.dateFormat
                },this.defaultItemsProp[key]),
                'java.util.Calendar': Ext.applyIf({
                    xtype: "datefield",
                    width: numberFieldWidth,
                    maxWidth: maxFieldWidth,
                    allowBlank: false,
                    format: this.dateFormat
                },this.defaultItemsProp[key])
            };
        }
        
        this.autoCompleteDefault = {        
            'single': Ext.applyIf({
                xtype: "tolomeo_uniquevaluescb",
                queryMode: "remote", // required as the combo store shouldn't be loaded before a field name is selected
                pageSize: this.autoCompleteCfg.pageSize || this.pageSize,
//                pageSize: this.autoCompleteCfg.autoCompleteMode == "remote" ? this.autoCompleteCfg.pageSize || this.pageSize : 0,
                typeAhead: true,
                forceSelection: false,
                remoteSort: true,
                triggerAction: "all",
                allowBlank: this.allowBlank,
                displayField: "value",
                valueField: "value",
                matchFieldWidth: false,
                listConfig:{
                	width: 200
                },
                minChars: this.autoCompleteCfg.minChars || 1,

//                resizable: true,
                listeners: {
                    select: function(combo, record) {
                        this.filter.value = combo.getValue();
                        this.fireEvent("change", this.filter);
                    },
                    blur: function(combo) {
                        this.filter.value = combo.getValue();
                        this.fireEvent("change", this.filter);
                    },
                    beforequery: function(evt) {
                        evt.combo.store.baseParams.start = 0;
                        //                        evt.combo.store.baseParams.query = evt.combo.getValue();
                        evt.combo.store.baseParams.query = this.autoCompleteCfg.autoCompleteMode == "remote" ? evt.combo.getValue() : "*";

                    },
                    scope: this
                },
                matchFieldWidth: false,
                anchor: "100%",
                flex:1
            },this.defaultItemsProp['single']),
            'lower': Ext.applyIf({
                xtype: "tolomeo_uniquevaluescb",
                queryMode: "remote", // required as the combo store shouldn't be loaded before a field name is selected
                pageSize: this.autoCompleteCfg.pageSize || this.pageSize,
//              pageSize: this.autoCompleteCfg.autoCompleteMode == "remote" ? this.autoCompleteCfg.pageSize || this.pageSize : 0,
                typeAhead: true,
                forceSelection: false,
                remoteSort: true,
                triggerAction: "all",
                allowBlank: this.allowBlank,
                displayField: "value",
                valueField: "value",
                minChars: this.autoCompleteCfg.minChars || 1,
//                resizable: true,
                listeners: {
                    select: function(combo, record) {
                        this.filter.lowerBoundary = combo.getValue();
                        this.fireEvent("change", this.filter);
                    },
                    blur: function(combo) {
                        this.filter.lowerBoundary = combo.getValue();
                        this.fireEvent("change", this.filter);
                    },
                    beforequery: function(evt) {
                        evt.combo.store.baseParams.start = 0;
//                        evt.combo.store.baseParams.query =  evt.combo.getValue();
                        evt.combo.store.baseParams.query = this.autoCompleteCfg.autoCompleteMode == "remote" ? evt.combo.getValue() : "*";
                    },
                    scope: this
                },
                matchFieldWidth: false,                
                anchor: "100%",
                flex:1
            },this.defaultItemsProp['lower']),
            'upper': Ext.applyIf({
                xtype: "tolomeo_uniquevaluescb",
                queryMode: "remote", // required as the combo store shouldn't be loaded before a field name is selected
        		pageSize: this.autoCompleteCfg.pageSize || this.pageSize,
//              pageSize: this.autoCompleteCfg.autoCompleteMode == "remote" ? this.autoCompleteCfg.pageSize || this.pageSize : 0,
                typeAhead: true,
                forceSelection: false,
                remoteSort: true,
                triggerAction: "all",
                allowBlank: this.allowBlank,
                displayField: "value",
                valueField: "value",
                minChars: this.autoCompleteCfg.minChars || 1,
//                resizable: true,
                listeners: {
                    select: function(combo, record) {
                        this.filter.upperBoundary = combo.getValue();
                        this.fireEvent("change", this.filter);
                    },
                    blur: function(combo) {
                        this.filter.upperBoundary = combo.getValue();
                        this.fireEvent("change", this.filter);
                    },
                    beforequery: function(evt) {
                        evt.combo.store.baseParams.start = 0;
//                        evt.combo.store.baseParams.query =  evt.combo.getValue();
                        evt.combo.store.baseParams.query = this.autoCompleteCfg.autoCompleteMode == "remote" ? evt.combo.getValue() : "*";

                    },
                    scope: this
                },
                matchFieldWidth: false,                
                anchor: "100%",
                flex: 1
            },this.defaultItemsProp['upper'])        
        };      
    },
    
	/**
     * Crea il filtro predefinito di comparazione. Questo metodo può essere sovrascritto per cambiare 
     * il filtro predefinito.
     * @return {OpenLayers.Filter} Di default ritorna un filtro di comparazione.
     * 
     */
    createDefaultFilter: function() {
        return new OpenLayers.Filter.Comparison({matchCase: !this.caseInsensitiveMatch});
    },
    
	/**
     * Crea il componente Ext destinato a contenere il valore delle proprietà.
     * @param {TolomeoExt.data.ToloUniqueValuesStore} store Store della combo box di auto completamento.
     * @param {String} layerName codTPN da usare com eparametro della richiesta.
     * @param {String} fieldName Nome della proprietà di cui ritornare i suggerimenti.
     * 
     */
    initUniqueValuesStore: function(store, layerName, fieldName, attributeLogicalName) {
        var params = {
            url: this.autoCompleteCfg.url,
            inputs: {
            	featureTypeName: layerName,
                fieldName: fieldName,
                attributeLogicalName: attributeLogicalName
            }
        };
        
        if(this.autoCompleteCfg.autoCompleteMode == "remote"){
        	Ext.applyIf(params, {
        		start: 0,
                limit: this.autoCompleteCfg.pageSize || this.pageSize
        	});
        }
        
        store.setParams(params);
    },
    
	/**
     * Imposta il tipo di filtro che si desidera.
     * @param {String} type Tipo del filtro da impostare.
     * 
     */
    setFilterType: function(type) {
        this.filter.type = type;
        
        // Ilike (ignore case)
        if(this.filter.type == "ilike"){
            this.filter.type = OpenLayers.Filter.Comparison.LIKE;
            this.filter.matchCase = false;
        }else{
            // default matches case. See OpenLayers.Filter.Comparison#matchCase
            this.filter.matchCase = !this.caseInsensitiveMatch; //true;
        }
    },

	/**
     * Cambia l'oggetto del filtro con uno nuovo che si desidera utilizzare.
     * @param {OpenLayers.Filter} filter Il filtro da impostare
     * 
     */
    setFilter: function(filter) {
        var previousType = this.filter.type;
        this.filter = filter;
        if (previousType !== filter.type) {
            this.setFilterType(filter.type);
        }
        this['property'].setValue(filter.property);
        this['type'].setValue(filter.type);
        if (filter.type === OpenLayers.Filter.Comparison.BETWEEN) {
            this['lowerBoundary'].setValue(filter.lowerBoundary);
            this['upperBoundary'].setValue(filter.upperBoundary);
        } else {
            this['value'].setValue(filter.value);
        }
        this.fireEvent("change", this.filter, this);
    }

});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.form');

/**
 * Una combo box utilizzata per visualizzare valori unici per un dato campo del layer.
 * Questo componente accetta tutte le configurazioni previste per una Ext.ComboBox
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.ToloUniqueValuesCombo', {
	
	extend: 'Ext.form.ComboBox',
	
	alias: 'widget.tolomeo_uniquevaluescb',
	
	/**
     * Restituisce i parametri usati nella richiesta ajax per il popolamento dello store.
     * @param {Object} q I parametri delo store per la richiesta.
	 * @return {Object} I patametri per la richiesta di popolamento dello store
     */
    getParams : function(q){
    	var superclass = this.superclass;
    	
        var params = superclass.getParams.call(this, q);
        Ext.apply(params, this.store.baseParams);
        return params;
    },
    
	/**
     * Inizializza la lista dei valori della paging toolbar
	 * 
     */
    initList : function() { 
    	// warning: overriding ComboBox private method
        this.superclass.initList.call(this);
        if (this.pageTb && this.pageTb instanceof Ext.PagingToolbar) {
            this.pageTb.afterPageText = "";
            this.pageTb.beforePageText = "";
            this.pageTb.displayMsg = "";
        }
    }
});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

// //////////////////////////////////////////////////////////////////////////
//  include widgets/form/spatialselector/BBOXToloSpatialSelectorMethod.js
//  include widgets/form/spatialselector/BufferToloSpatialSelectorMethod.js
//  include widgets/form/spatialselector/CircleToloSpatialSelectorMethod.js
//  include widgets/form/spatialselector/PolygonToloSpatialSelectorMethod.js
/////////////////////////////////////////////////////////////////////////////

Ext.ns('TolomeoExt.widgets.form.spatialselector');

/**
 * Plugin comune per la selezione spaziale.
 * Widgets conosciute: 
 *    <ul>
 *       <li>BBOXToloSpatialSelectorMethod: `widget.tolomeo_spatial_bbox_selector` ptype</li>
 *       <li>BufferToloSpatialSelectorMethod: `widget.tolomeo_spatial_buffer_selectorr` ptype</li>
 *       <li>CircleToloSpatialSelectorMethod: `widget.tolomeo_spatial_circle_selector` ptype</li>
 *       <li>PolygonToloSpatialSelectorMethod: `widget.tolomeo_spatial_polygon_selector` ptype</li>
 * 	  </ul>
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod', {
	
	extend: 'Ext.Container',

    /**
     * @cfg {String} name.
     * Nome da mostrare nella combo box di selezione spaziale.
     */

    /**
     * @cfg {String} label.
     * Etichetta da mostrare nella combo box di selezione spaziale.
     */

    /**
     * @cfg {Object} output.
     * Configurazione di output per questo plugin.
     */

    /**
     * @cfg {OpenLayers.Geometry} currentGeometry.
     * Rappresenta la geometria selezionata.
     */

    /**
     * @cfg {OpenLayers.Geometry} filterGeometryName.
     * Rappresenta il nome del campo geometrico da usare nel filtro.
     */
   
 	/**
     * @property {Boolean} zoomToCurrentExtent [zoomToCurrentExtent="false"]
     * Flag per stabilire lo zoom all'extent della geometria selezionata.
     */
	zoomToCurrentExtent: false,

    /**
     * @property {Object} defaultStyle.
     * Configurazione del OpenLayer.Style predefinito usato come stile del BBOX su mappa.
     */
	defaultStyle : {
        "fillColor"   : "#FFFFFF",
        "strokeColor" : "#FF0000",
        "fillOpacity" : 0.5,
        "strokeWidth" : 1
	},

    /**
     * @property {Object} selectStyle.
     * Configurazione del OpenLayer.Style di selezione usato come stile del BBOX su mappa.
     */
	selectStyle : {
        "fillColor"   : "#FFFFFF",
        "strokeColor" : "#FF0000",
        "fillOpacity" : 0.5,
        "strokeWidth" : 1
	},

    /**
     * @property {Object} temporaryStyle.
     * Configurazione del OpenLayer.Style temporaneo usato come stile del BBOX su mappa.
     */
	temporaryStyle : {
		"strokeColor": "#ee9900",
		"fillColor": "#ee9900",
		"fillOpacity": 0.4,
		"strokeWidth": 1
	},
	
 	/**
     * @property {Boolean} addGeometryOperation [addGeometryOperation="true"]
     * Flag per stabilire se aggiungere o meno il tool di selezione dell'operazione geometrica per la selezione spaziale scelta.
     */
	addGeometryOperation: true,

 	/**
     * @cfg {Object} geometryOperations.
     * Lista delle operazioni geometriche consentite.
     * 
     * @example
	 *	geometryOperations:[{
	 *		name: "INTERSECTS",
	 *		label: "INTERSECTS",
	 *		value: OpenLayers.Filter.Spatial.INTERSECTS
	 *	},{
	 *		name: "BBOX",
	 *		label: "BBOX",
	 *		value: OpenLayers.Filter.Spatial.BBOX
	 *	},{
 	 *		name: "CONTAINS",
	 *		label: "CONTAINS",
	 *		value: OpenLayers.Filter.Spatial.CONTAINS
	 *	},{
	 *		name: "DWITHIN",
	 *		label: "DWITHIN",
	 *		value: OpenLayers.Filter.Spatial.DWITHIN
	 *	},{
	 *		name: "WITHIN",
	 *		label: "WITHIN",
	 *		value: OpenLayers.Filter.Spatial.WITHIN
	 *	}]
     */
	geometryOperations:null,

    /**
     * @property {OpenLayers.Filter.Spatial} defaultGeometryOperation.
     * Operazione geometrica selezionata di default.
     */
	defaultGeometryOperation: OpenLayers.Filter.Spatial.INTERSECTS,

    /**
     * @property {String} geometryOperationText.
     * Testo da mostrare per l'etichetta della operazione geometrica.
     */
	geometryOperationText: null,

    /**
     * @property {String} geometryOperationEmptyText.
     * Testo da mostrare per la combo box della operazione geometrica se non valorizzata.
     */
	geometryOperationEmptyText: null,

    /**
     * @property {String} distanceTitleText.
     * Testo da mostrare per il fieldset della distanza.
     */
	distanceTitleText: null,
	
	/**
     * @property {String} distanceLabelText.
     * Etichetta da mostrare per il valore della distanza.
     */
	distanceLabelText: null,

    /**
     * @property {String} distanceUnitsTitleText.
     * Testo da mostrare per il campo delle unità relative al campo distanza.
     */
	distanceUnitsTitleText: null,

    /**
     * @property {String} noOperationTitleText.
     * Messaggio di operazione non valida.
     */
	noOperationTitleText: null,

    /**
     * @property {String} noOperationMsgText.
     * Messaggio per operazione non selezionata.
     */
	noOperationMsgText: null,

    /**
     * @property {String} noCompleteMsgText.
     * Messaggio per form non completa.
     */
	noCompleteMsgText: null,
	
	/**
	 * @cfg {TolomeoExt.events.ToloQueryBuilderEvtManager} qbEventManager (required)
	 * Gestore di eventi per il query builder.
	 */
	qbEventManager: null,

	/**
     * Crea un nuovo TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	constructor : function(config) {
		Ext.apply(this, config);		
		this.callParent(arguments);
	},

	/**
     * Inizializza un nuovo TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config) {   
		Ext.apply(this, config);
		
		
		this.geometryOperations = [{
			name: "INTERSECTS",
			label: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.INTERSECTS"),
			tipTitle: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.INTERSECTS.title"),
			tipText: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.INTERSECTS.text"),
			value: OpenLayers.Filter.Spatial.INTERSECTS
		}/*
		,{
			name: "BBOX",
			label: "Bounding Box",
			value: OpenLayers.Filter.Spatial.BBOX
		}
		*/
		,{
			name: "DWITHIN",
			label: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.DWITHIN"),
			tipTitle: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.DWITHIN.title"),
			tipText: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.DWITHIN.text"),
			value: OpenLayers.Filter.Spatial.DWITHIN
		},{
			name: "WITHIN",
			label: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.WITHIN"),
			tipTitle: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.WITHIN.title"),
			tipText: ToloI18n.getMsg("ToloSpatialSelectorMethod.geoOp.WITHIN.text"),
			value: OpenLayers.Filter.Spatial.WITHIN
		}];
		
		this.geometryOperationText = ToloI18n.getMsg("ToloSpatialSelectorMethod.geometryOperationText");
		this.geometryOperationEmptyText = ToloI18n.getMsg("ToloSpatialSelectorMethod.geometryOperationEmptyText");
		this.distanceTitleText = ToloI18n.getMsg("ToloSpatialSelectorMethod.distanceTitleText");
		this.distanceLabelText = ToloI18n.getMsg("ToloSpatialSelectorMethod.distanceLabelText");
		this.distanceUnitsTitleText = ToloI18n.getMsg("ToloSpatialSelectorMethod.distanceUnitsTitleText");
		this.noOperationTitleText = ToloI18n.getMsg("ToloSpatialSelectorMethod.noOperationTitleText");
		this.noOperationMsgText = ToloI18n.getMsg("ToloSpatialSelectorMethod.noOperationMsgText");
		this.noCompleteMsgText = ToloI18n.getMsg("ToloSpatialSelectorMethod.noCompleteMsgText");
		
		

		if(!this.output){
			this.output = this;
		}

		if(this.addGeometryOperation){
			if (!this.items){
				this.items = [];
			}

			this.items.push({
				xtype: 'fieldset',
				ref: "geometryOperationFieldset",
				title: this.geometryOperationText,
                checkboxToggle: true,
                collapsed : true,
				items: [this.getGeometryOperationCombo()]
			});
			
			this.items.push(this.getDistanceFieldset());
		}

		this.output.addEvents(
				"geometrySelect"
		);	
		
		this.callParent();
		
        this.on("added", function(scope){
        	scope.geometryOperationFieldset = scope.query('fieldset[ref=geometryOperationFieldset]')[0];
        	scope.geometryOperation = scope.query('combo[ref=geometryOperation]')[0];
        	scope.distanceFieldset = scope.query('fieldset[ref=distanceFieldset]')[0];
        	scope.distance = scope.query('numberfield[ref="distance"]')[0];
        	//scope.dunits = scope.query('textfield[ref=dunits]')[0];
        });
    },

	/**
     * Genera un oggetto per la combo di selezione.
     * @return {Object} l'oggetto selezionato dalla combo.
     */
	getSelectionMethodItem: function(){
        return {
        	label: this.label, 
        	name: this.name
        };
	},

	/**
     * Genera un filtro per il metodo si selezione.
     * @return {OpenLayers.Filter} Il filtro impostato dall'utente.
     */
	getQueryFilter: function(){
		var operation = null;
		
		if(this.addGeometryOperation && !this.geometryOperationFieldset.collapsed){
			if(this.geometryOperation.isValid() ){
				operation = this.geometryOperation.getValue();
			}else{
                Ext.Msg.show({
                    title: this.noOperationTitleText,
                    msg: this.noOperationMsgText,
                    buttons: Ext.Msg.OK,
                    icon: Ext.MessageBox.ERROR
                });
				return null;
			}
		}else{
			operation = OpenLayers.Filter.Spatial.INTERSECTS;
		}
		
		if(this.currentGeometry){
			switch (operation){
				case OpenLayers.Filter.Spatial.CONTAINS:
				case OpenLayers.Filter.Spatial.INTERSECTS:
					this.currentFilter = new OpenLayers.Filter.Spatial({
						type: operation,
						property:  this.filterGeometryName,
						value: this.currentGeometry,
						bounds: this.currentGeometry.getBounds()
					});
					break;
				case OpenLayers.Filter.Spatial.WITHIN:
					this.currentFilter = new OpenLayers.Filter.Spatial({
						type: operation,
						property:  this.filterGeometryName,
						value: this.currentGeometry
					});
					break;
				case OpenLayers.Filter.Spatial.DWITHIN:
					if(this.distance.isValid()
						/*&& this.dunits.isValid()*/){
						this.currentFilter = new OpenLayers.Filter.Spatial({
							type: operation,
							property:  this.filterGeometryName,
					        distanceUnits: "m", //this.dunits.getValue(),
					        distance: this.distance.getValue(),
							value: this.currentGeometry
						});
					}else{
		                Ext.Msg.show({
		                    title: this.noOperationTitleText,
		                    msg: this.noCompleteMsgText,
		                    buttons: Ext.Msg.OK,
		                    icon: Ext.MessageBox.ERROR
		                });
		                return null;
					}
					break;
				case OpenLayers.Filter.Spatial.BBOX:
				default: 
					this.currentFilter = new OpenLayers.Filter.Spatial({
						type: OpenLayers.Filter.Spatial.BBOX,
						property:  this.filterGeometryName,
						value: this.currentGeometry.getBounds()
					});
			}
			
		}else{
	        this.currentFilter = null;
		}
		
		return this.currentFilter;
	},

	/**
     * Attiva il plugin.
     * 
     */
	activate: function(){
		this.reset();
		this.doLayout();
		this.show();
	},

	/**
     * Disattiva il plugin.
     * 
     */
	deactivate: function(){
		this.reset();
		this.hide();
	},

	/**
     * Reimposta il componente (filtro e geometria).
     * 
     */
    reset: function(){
    	this.currentGeometry = null;
    	this.currentFilter = null;
    },

	/** api: method[setCurrentGeometry]
     *  :arg geometry: ``Object`` The geometry to be setted as current geometry.
     *  Set current geometry
	 */
    setCurrentGeometry: function(geometry){
		this.currentGeometry = geometry;
		
    	if (geometry) {
			if (this.zoomToCurrentExtent && geometry && geometry.getBounds) {
				var dataExtent = geometry.getBounds();
				
				// create an event to manage the zoom to extent
				this.qbEventManager.fireEvents("zoomtomapextent", {dataExtent: dataExtent});
			}

			this.output.fireEvent("geometrySelect", geometry);
		} 
    },

	/**
     * Genera la combo box Ext per la selezione dell'operazione geometrica.
     * @return {Ext.form.ComboBox} La combo box di selezione dell'operazione geometrica.
     */
	getGeometryOperationCombo: function() {
		var geometryOperationMethodCombo = Ext.create('Ext.form.ComboBox', {
			ref : 'geometryOperation',
			width: 220,
			labelStyle: 'width: 70px;',
			typeAhead : true,
			forceSelection: true, 
			queryMode: 'local',
			triggerAction: 'all',
			emptyText : this.geometryOperationEmptyText,
			selectOnFocus: true,
			editable:false,
			fieldLabel : this.geometryOperationText,
			name : 'geometryOperation',
			displayField : 'label',
			valueField : 'value',
			readOnly : false,
			lazyRender : false,
			value: this.defaultGeometryOperation,
			allowBlank : false,
			listConfig: {
		 
		        // Custom rendering template for each item
		        getInnerTpl: function() {                	        
		        	// return '{[(values.tipTitle || values.tipText)  ? values.text + " <div data-qtitle=\\"" + values.tipTitle + "\\"  data-qtip=\\"" + values.tipText + "\\" style=\\"color:gray; border-bottom: dashed 1px gray; border-top: dashed 1px gray; \\">" + values.tipText + "</div>" : values.text]}';
		        	return '{[(values.tipTitle || values.tipText)  ? " <div data-qtitle=\\"" + values.tipTitle + "\\"  data-qtip=\\"" + values.tipText + "\\" >" + values.label + "</div>" : values.label]}';
		        }
			},
			
			store : Ext.create('Ext.data.JsonStore', {
				autoLoad : true,
				fields : [{
					name : 'name',
					dataIndex : 'name'
				}, {
					name : 'label',
					dataIndex : 'label'
				}, {
					name : 'value',
					dataIndex : 'value'
				}, {
					name : 'tipTitle',
					dataIndex : 'tipTitle'
				}, {
					name : 'tipText',
					dataIndex : 'tipText'
				}],
				data : this.geometryOperations
			}),
			listeners : {
				// Show/Hide distance units for DWITHIN
				select : function(c, record, index) {
					if(c.getValue() == OpenLayers.Filter.Spatial.DWITHIN){
						this.distanceFieldset.show();
					}else if(this.distanceFieldset.isVisible()){
						this.distanceFieldset.hide();
					}
				},
				scope : this
			}
		});
		 
		return geometryOperationMethodCombo;
	},

	/**
     * Genera la combo box Ext per la selezione della distanza (specifica selezione geometrica vedi "DWITHIN").
     * @return {Ext.form.FieldSet} il FieldSet per l'impostazione della distanza.
     */
	getDistanceFieldset: function(){
		return {
			xtype: 'fieldset',
			title: this.distanceTitleText,
			ref: "distanceFieldset",
			hidden: true,
			items: [/*{
				xtype: "textfield",
				fieldLabel: this.distanceUnitsTitleText,
				name: "dunits",
				ref: "dunits",
				labelStyle: 'width: 90px;',
				width: 200,
				allowBlank: false
			},*/{
				xtype: "numberfield",
				fieldLabel: this.distanceLabelText,
				name: "distance",
				ref: "distance",
				labelStyle: 'width: 90px;',
				width: 200,
				allowBlank: false
			}]/*,
			listeners:{
				scope: this,
			    afterlayout: function(fieldset, options){
					var dunits = this.query('textfield[ref=dunits]')[0];
					if(this.qbEventManager){
						this.qbEventManager.fireEvent("setmapunitsvaluefield", this.dunits);
					}
				}
			}*/
		}
	},
	
	setDecimalPrecision: function(decimalPrecision){
		return;
	}
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.form.spatialselector');

/**
 * Plugin per la selezione poligonale
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.spatialselector.ToloPolygonSpatialSelectorMethod', {
	
	extend: 'TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod',
	
	alias: 'widget.tolomeo_spatial_polygon_selector',
	
	requires: [
       'TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod'
	],

    /**
     * @cfg {String} name.
     * Nome da mostrare nella combo box di selezione spaziale.
     */
	name  : null,
	
	buttonCls : 'draw-polygon-button',

    /**
     * @cfg {String} label.
     * Etichetta da mostrare nella combo box di selezione spaziale.
     */
	label : null,
	
	initComponent: function(config) {   
				
    	this.name = ToloI18n.getMsg("ToloPolygonSpatialSelectorMethod.name");
    	this.label = ToloI18n.getMsg("ToloPolygonSpatialSelectorMethod.label");
    	
		var displayProjection = this.displayProjection;
		var me = this;
		
    	this.output = Ext.create('Ext.Button', {    		
            text: ToloI18n.getMsg("ToloPolygonSpatialSelectorMethod.output"),
            tooltip: ToloI18n.getMsg("ToloPolygonSpatialSelectorMethod.tooltip"),
            enableToggle: true,            
            iconCls: this.buttonCls,            
            height: 40,
            width: 100,
            scale: 'large',
            listeners: {
                scope: this, 
                toggle: function(button, pressed) {
                    if(pressed){      
                        me.unfreeze();
                    }else{
                        me.freeze();
                    }
                }
            }
        }); 

    	this.items = [{
    		type: 'fieldcontainer',       		
    		margin: 10,
    		border: false,
    		layout: {
    		        type: 'hbox',
    		        pack: 'center'
    		        
    		},
	    	items: [this.output]
    	}];
    	
    	this.active = false;

    	this.callParent(arguments);
    },


	/**
     * Attiva il controllo.
     * 
     */
	activate: function(){
		TolomeoExt.widgets.form.spatialselector.ToloPolygonSpatialSelectorMethod.superclass.activate.call(this);
		this.output.enable();		
	},

	/**
     * Restituisce il controllo di disegno di questo componente.
     * 
     */
	getDrawControl: function(){
		return new OpenLayers.Control.DrawFeature(
            this.drawings,
            OpenLayers.Handler.Polygon
        );
	},

	/**
     * Disattiva il controllo.
     * 
     */
	deactivate: function(){
		TolomeoExt.widgets.form.spatialselector.ToloPolygonSpatialSelectorMethod.superclass.deactivate.call(this);
		if(this.draw){
			this.draw.deactivate();	
		}
		
		if(this.qbEventManager){
			this.qbEventManager.fireEvent("polygonSpatialSelectorDeactive", this);
		}
		
		this.output.disable();
		
		this.active = false;
		
		/*
		if (this.drawings) {
			if(this.qbEventManager){
				this.qbEventManager.fireEvent("removelayer", this.drawings);
			}
			
			this.drawings = null;
		}
		*/
	},

	/**
     * Reimposta il controllo di sidegno poligonale.
     * 
     */
    reset: function(){    	
    	TolomeoExt.widgets.form.spatialselector.ToloPolygonSpatialSelectorMethod.superclass.reset.call(this);
    	
		if(this.drawings){
			this.drawings.removeAllFeatures();
		}
		
		if(this.persistance){
			this.persistance.removeAllFeatures();
		}
    },
	
	freeze: function(){
		if(this.draw){
			this.draw.deactivate();	
		}		
		
		if(this.output.pressed){
			this.output.toggle();
		}
	},
	
	unfreeze: function(){
		
		if(!this.active) {
			
			if(this.qbEventManager){
				this.qbEventManager.fireEvent("polygonSpatialSelectorActive", this);
			}			
			this.active = true;
			
		} else {
			
			if(this.persistance){
				this.persistance.removeAllFeatures();
			}
			
			if(this.draw){
				this.draw.activate();	
			}
			
		}
						
	}
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.namespace('TolomeoExt.widgets.form.spatialselector');

/**
 * Plugin per la selezione di una area di interesse a Bounding Box (BBOX).
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.spatialselector.ToloBBOXSpatialSelectorMethod', {
		
	extend: 'TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod',

	alias : 'widget.tolomeo_spatial_bbox_selector',
	
	requires: [
       'TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod'
	],

    /**
     * @cfg {String} latitudeEmptyText [displayProjection="null"]
     * La proiezione per il display delle coordinate (se null si usa la proiezione dell mappa).
     */
    displayProjection: null,
    
    /**
     * @cfg {String} name.
     * Nome da mostrare nella combo box di selezione spaziale.
     */
	name  : null,

    /**
     * @cfg {String} label.
     * Etichetta da mostrare nella combo box di selezione spaziale.
     */
	label : null,

 	/**
     * @cfg {Object} spatialFilterOptions.
     * Opzioni di configurazione per i campi di coordinata (valori massimi e minini consentiti per i campi).
     * 
     * @example
	 *    spatialFilterOptions: {
	 *	        lonMax: 180,   
	 *	        lonMin: -180,
	 *	        latMax: 90,   
	 *	        latMin: -90  
	 *	  }
     */
	spatialFilterOptions : {
		lonMax : 20037508.34, //90,
		lonMin : -20037508.34, //-90,
		latMax : 20037508.34, //180,
		latMin : -20037508.34 //-180
	},

 	/**
     * @property {String} northLabel.
     * Testo dell'etichetta per la coordinata Nord.
     */
    northLabel: null,
    
 	/**
     * @property {String} westLabel.
     * Testo dell'etichetta per la coordinata Ovest.
     */
    westLabel: null,
    
 	/**
     * @property {String} eastLabel.
     * Testo dell'etichetta per la coordinata Est.
     */
    eastLabel: null,
    
 	/**
     * @property {String} southLabel.
     * Testo dell'etichetta per la coordinata Sud.
     */
    southLabel: null,

 	/**
     * @property {String} setAoiTitle.
     * Titolo del field set di contenimento.
     */
	setAoiTitle : null,

 	/**
     * @property {String} setAoiText.
     * Testo di etichetta per il pulsante di attivazione del controllo di disegno del BOX.
     */
    setAoiText: null,

 	/**
     * @property {String} setAoiTooltip.
     * Testo per il tooltip del pulsante di attivazione del controllo di disegno del BOX.
     */
    setAoiTooltip: null,

	/**
     * Inizializza un nuovo TolomeoExt.widgets.form.spatialselector.ToloBBOXSpatialSelectorMethod.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config) {
    	
    	this.name  = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.name");
    	this.label = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.label");
    	
        this.northLabel = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.northLabel");
        this.westLabel = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.westLabel");
        this.eastLabel = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.eastLabel");
        this.southLabel = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.southLabel");
        this.setAoiTitle = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.setAoiTitle");
        this.setAoiText = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.setAoiText");
        this.setAoiTooltip = ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.setAoiTooltip");
    	
    	var displayProjection = this.displayProjection;
		
    	// ///////////////////////////////////////////
		// Spatial AOI Selector FieldSet
		// ///////////////////////////////////////////
		var confbbox = {
            map: null, 
            padding: '5 0 5 5',
            outputSRS : this.displayProjection  || null, 
            spatialFilterOptions: this.spatialFilterOptions,
            ref: "spatialFieldset",
            id: this.id + "_bbox",
            defaultStyle: this.defaultStyle,
            selectStyle: this.selectStyle,
            temporaryStyle: this.temporaryStyle,
            anchor: "100%",
            title: this.setAoiTitle,
		    northLabel:this.northLabel,
		    westLabel:this.westLabel,
		    eastLabel:this.eastLabel,
		    southLabel:this.southLabel,
		    setAoiText: this.setAoiText,
		    setAoiTooltip: this.setAoiTooltip,
		    waitEPSGMsg: ToloI18n.getMsg("ToloBBOXSpatialSelectorMethod.waitEPSGMsg")
        };

    	this.output = Ext.create('TolomeoExt.widgets.form.ToloBBOXFieldset', confbbox);

    	this.items = [this.output];

    	this.callParent();
    },

	/**
     * Attiva il controllo.
     * 
     */
	activate: function(){
		TolomeoExt.widgets.form.spatialselector.ToloBBOXSpatialSelectorMethod.superclass.activate.call(this);
		if(this.output){
			this.output.enable();
		}
	},

	/**
     * Disattiva il controllo.
     * 
     */
	deactivate: function(){
		TolomeoExt.widgets.form.spatialselector.ToloBBOXSpatialSelectorMethod.superclass.deactivate.call(this);
		if(this.output){
			if(this.qbEventManager){
				this.qbEventManager.fireEvent("removelayer", this.output.layerName);
			}
			this.output.disable();
		}
	},

	/**
     * Reimposta il controllo di disegno del BBOX.
     * 
     */
    reset: function(){
    	TolomeoExt.widgets.form.spatialselector.ToloBBOXSpatialSelectorMethod.superclass.reset.call(this);
    	
		if(this.qbEventManager){
			this.qbEventManager.fireEvent("removelayer", this.output.layerName);
		}
    	this.output.reset();
    },

	setDecimalPrecision: function(decimalPrecision){
		this.output.setDecimalPrecision(decimalPrecision);
	}

});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.form.spatialselector');

/**
 * Plugin per la selezione di una area di interesse a buffer.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.spatialselector.ToloBufferSpatialSelectorMethod',  {
	
	extend: 'TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod',

	alias: 'widget.tolomeo_spatial_buffer_selector',
	
	requires: [
       'TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod'
	],

    /**
     * @cfg {String} name.
     * Nome da mostrare nella combo box di selezione spaziale.
     */
	name: null,

    /**
     * @cfg {String} label.
     * Etichetta da mostrare nella combo box di selezione spaziale.
     */
	label: null,

    /**
     * @cfg {String} latitudeEmptyText.
     * Testo da mostrare se ili campo Y (latitude) non è valorizzato.
     */
    latitudeEmptyText: null,

    /**
     * @cfg {String} longitudeEmptyText.
     * Testo da mostrare se ili campo X (longitude) non è valorizzato.
     */
    longitudeEmptyText: null,

	/**
	 * @cfg {Object} bufferOptions 
	 * Opzioni di configurazione per la selezione del buffer.
	 *
	 * @example
	 *	bufferOptions : {
	 *		"minValue": 1,
	 *		"maxValue": 1000, 
	 *			"decimalPrecision": 2,
	 *		"distanceUnits": "m"
	 *	}
	 */
	bufferOptions : {
		"minValue": 1,
		"maxValue": 5000,
		"decimalPrecision": 2,
		"distanceUnits": "m",
		"outputSRS": "EPSG:3003"
	},
	
    /**
     * @cfg {Boolean} geodesic.
     * 
     */
	geodesic: true,

	/**
     * Inizializza un nuovo TolomeoExt.widgets.form.spatialselector.ToloBufferSpatialSelectorMethod.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    initComponent: function(config) {
    	
    	this.name = ToloI18n.getMsg("ToloBufferSpatialSelectorMethod.name");
    	this.label = ToloI18n.getMsg("ToloBufferSpatialSelectorMethod.label");
    	this.latitudeEmptyText = ToloI18n.getMsg("ToloBufferSpatialSelectorMethod.latitudeEmptyText");
    	this.longitudeEmptyText = ToloI18n.getMsg("ToloBufferSpatialSelectorMethod.longitudeEmptyText");

		// ///////////////////////////////////////////
		// Spatial Buffer Selector FieldSet
		// ///////////////////////////////////////////
		this.bufferFieldset = new TolomeoExt.widgets.form.ToloBufferFieldset({
			id: this.id + "bufferFieldset",
			map: null,
			minValue: this.bufferOptions.minValue,
            maxValue: this.bufferOptions.maxValue,
		    decimalPrecision: this.bufferOptions.decimalPrecision,
		    outputSRS : this.bufferOptions.outputSRS, 
			selectStyle: this.selectStyle,
			geodesic: this.geodesic != undefined ?  this.geodesic : false,
			latitudeEmptyText: this.latitudeEmptyText,
			longitudeEmptyText: this.longitudeEmptyText,
			qbEventManager: this.qbEventManager			
		});
		
		this.bufferFieldset.on("bufferadded", function(evt, feature){
			this.setCurrentGeometry(feature.geometry);
		}, this);

	    this.bufferFieldset.on("bufferremoved", function(evt, feature){
			this.setCurrentGeometry(null);
		}, this);
	    
	    this.bufferFieldset.on("afterlayout", function(evt){
	    	this.qbEventManager.fireEvent("addcoordinatepickercontrol", this.bufferFieldset.coordinatePicker);
		}, this);

    	this.output = this;

    	this.items = [this.bufferFieldset];

    	this.callParent();
    },

	/**
     * Attiva il controllo.
     * 
     */
	activate: function(){
		TolomeoExt.widgets.form.spatialselector.ToloBufferSpatialSelectorMethod.superclass.activate.call(this);
		if(this.output){
			this.output.enable();
			if(Ext.isIE){
				this.output.doLayout();
			}
		}
	},

	/**
     * Disattiva il controllo.
     * 
     */
	deactivate: function(){
		TolomeoExt.widgets.form.spatialselector.ToloBufferSpatialSelectorMethod.superclass.deactivate.call(this);
		if(this.output){
			this.bufferFieldset.resetPointSelection();
			this.bufferFieldset.coordinatePicker.toggleButton(false);
			this.output.hide();
			this.output.disable();
		}
	},

	/**
     * Reimposta il controllo di disegno del buffer.
     * 
     */
    reset: function(){
    	TolomeoExt.widgets.form.spatialselector.ToloBufferSpatialSelectorMethod.superclass.reset.call(this);
		if(this.output){
			this.bufferFieldset.resetPointSelection();
			this.bufferFieldset.coordinatePicker.toggleButton(false);
		}
    },

	setDecimalPrecision: function(decimalPrecision){
		this.bufferFieldset.setDecimalPrecision(decimalPrecision);
	}

});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.widgets.form.spatialselector');

/**
 * Plugin per la selezione di una area di interesse circolare.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.widgets.form.spatialselector.ToloCircleSpatialSelectorMethod', {
	
	extend: 'TolomeoExt.widgets.form.spatialselector.ToloPolygonSpatialSelectorMethod',

	alias: 'widget.tolomeo_spatial_circle_selector',
	
	requires: [
       'TolomeoExt.widgets.form.spatialselector.ToloSpatialSelectorMethod'
	],
  
    /**
     * @cfg {String} name.
     * Nome da mostrare nella combo box di selezione spaziale.
     */
	name  : null,
	
	buttonCls : 'draw-circle-button',

    /**
     * @cfg {String} label.
     * Etichetta da mostrare nella combo box di selezione spaziale.
     */
	label : null,

	initComponent: function(config) {
		this.callParent();
		this.name = ToloI18n.getMsg("ToloCircleSpatialSelectorMethod.name");
		this.label = ToloI18n.getMsg("ToloCircleSpatialSelectorMethod.label");
	},
	
	/**
     * Restituisce il controllo di disegno di questo componente.
     * 
     */
	getDrawControl: function(){
        var polyOptions = {sides: 100};
        
        return new OpenLayers.Control.DrawFeature(
            this.drawings,
            OpenLayers.Handler.RegularPolygon,
            {
                handlerOptions: polyOptions
            }
        );
	},

	/**
     * Reimposta il controllo di disegno poligonale.
     * 
     */
    reset: function(){
    	TolomeoExt.widgets.form.spatialselector.ToloCircleSpatialSelectorMethod.superclass.reset.call(this);
		if(this.circleCentroidLayer){
			this.circleCentroidLayer.removeAllFeatures();
		}
    }

});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Crea un poligono regolar dato il raggio. Utile per la creazione di cerchi gedetici.
 * @param {Object} origin Corrisponde al centro del poligono.
 * @param {Number} radius Rappresenta il raggio del poligono regolare.
 * @param {Number} sides Rappresenta il numero di lati per determinare il livello di aprossimazione 
                   del poligono regolare 20 approssima un cerchio. 
 * @param {Number} rotation angolo di rotazione in gradi.
 * @param {OpenLayers.Projection} projection Sistema di proiezione delle coordinate.
 */
OpenLayers.Geometry.Polygon.createGeodesicPolygon = function(origin, radius, sides, rotation, projection){
	if (projection.getCode() !== "EPSG:4326") {
		origin.transform(projection, new OpenLayers.Projection("EPSG:4326"));
	}
	var latlon = new OpenLayers.LonLat(origin.x, origin.y);
	
	var angle;
	var new_lonlat, geom_point;
	var points = [];
	
	for (var i = 0; i < sides; i++) {
		angle = (i * 360 / sides) + rotation;
		new_lonlat = OpenLayers.Util.destinationVincenty(latlon, angle, radius);
		new_lonlat.transform(new OpenLayers.Projection("EPSG:4326"), projection);
		geom_point = new OpenLayers.Geometry.Point(new_lonlat.lon, new_lonlat.lat);
		points.push(geom_point);
	}
	var ring = new OpenLayers.Geometry.LinearRing(points);
	return new OpenLayers.Geometry.Polygon([ring]);
};

Ext.ns('TolomeoExt.events');

/**
 * Plugin per la gesitione degli eventi che coinvolgono il query builder.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.events.ToloQueryBuilderEvtManager', {
	
	extend: 'Ext.util.Observable',
	
	id: "qb_event_manager",
	
	/**
     * Crea un nuovo TolomeoExt.events.ToloQueryBuilderEvtManager.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	constructor: function(config) {
		this.callParent(arguments);
		
		Ext.apply(this, config);
		
		this.addEvents(
		        /**
				 * @event
				 * Lanciato successivamente al disegno del box.
				 */
				"afterboxlayout",
				/**
				 * @event
				 * Lanciato dai componenti che lo necessitano per lo zoom all'extent specificato.
				 */
				"zoomtomapextent",
				/**
				 * @event
				 * Lanciato dai componenti che lo necessitano per la rimozione di un layer della mappa.
				 */
				"removelayer",
				/**
				 * @event
				 * Lanciato per l'aggiunta del controllo di selezione delle coordiante su mappa.
				 */
				"addcoordinatepickercontrol",
				/**
				 * @event
				 * Lanciato per l'aggiornemento del punto sulla mappa.
				 */
				"updatemappoint",
				/**
				 * @event
				 * Lanciato successivamente al disegno del box.
				 */
				"drawbuffer",
				/**
				 * @event
				 * Lanciato per l'attivazione del controllo di selezione spaziale.
				 */
				"polygonSpatialSelectorActive",
				/**
				 * @event
				 * Lanciato per l'impostazione delle unit di misura.
				 */
				"setmapvaluefield",
				/**
				 * @event
				 * Lanciato a seguito di una operazione di spostamento della mappa.
				 */
				"mapmoved",
				/**
				 * @event
				 * Lanciato per l'agginta di un layer vetoriale.
				 */
				"addvectorlayer",
				/**
				 * @event
				 * Lanciato per impostare le unità della mappa nei tool che lo richiedono.
				 */
				"setmapunitsvaluefield"
		);	
		
		this.on("afterboxlayout", this.onAfterBoxLayout);
		this.on("zoomtomapextent", this.zoomToMapExtent);
		this.on("removelayer", this.removeLayer);
		this.on("addlayer", this.addLayer);
		this.on("addcoordinatepickercontrol", this.addCoordinatePickerControl);
		this.on("updatemappoint", this.updateMapPoint);
		this.on("drawbuffer", this.drawBuffer);
		this.on("polygonspatialselectoractive", this.polygonSpatialSelectorActive);
		this.on("polygonspatialselectorDeactive", this.polygonSpatialSelectorDeactive);
		this.on("setmapunitsvaluefield", this.setMapUnitsValueField);
	},
	
	/**
     * Imposta la mappa per le operaioni interne di gestione.
     * @param {OpenLayers.Map} map La mappa di TolomeoExt.
     */
	setMap: function(map){
		this.map = map;		
		this.map.events.register("moveend", this, function(){
			this.fireEvent("mapmoved", this.map.getExtent());
		});
	},
	
	/**
     * Aggiunge un dato layer alla mappa.
     * @param {OpenLayers.Layer} layer Layer OpenLayers WMS o Vector.
     */
	addLayer: function(layer){
		if(layer && this.map){
			//
			// check if already exists if yes remove it
			//
			var lay = this.map.getLayersByName(layer.name)[0];    	        
	        if(lay){
	            this.map.removeLayer(lay);
	        }	        
	        
			this.map.addLayer(layer);
		}
	},
	
	/**
     * Rimuove un dato layer dalla mappa.
     * @param {OpenLayers.Layer} layer Layer OpenLayers WMS o Vector.
     */
	removeLayer: function(layer){
		
		var lay = this.getLayer(layer);				
		
		if(!lay || (lay instanceof OpenLayers.Layer.Vector && lay.features.length < 1)){
			return;
		}
				        
	    this.map.removeLayer(lay);	       
		
		/*
		if(layer && this.map){
			var lay;
			if(typeof layer === 'string'){
				lay = this.map.getLayersByName(layer)[0];
			}else{
				lay = layer;
			}        
	        
			var remove = lay ? true : false;
			if(lay && lay instanceof OpenLayers.Layer.Vector && lay.features.length < 1){
				remove = false;
			}
			
	        if(remove){
	            this.map.removeLayer(lay);
	        }
		}
		*/
	}, 
	
	/**
     * Rimuove un dato layer dalla mappa.
     * @param {OpenLayers.Layer} layer Layer OpenLayers WMS o Vector.
     */
	getLayer: function(layer){
		if(layer && this.map){
			var lay;
			if(typeof layer === 'string'){
				lay = this.map.getLayersByName(layer)[0];
			}else{
				lay = layer;
			}
			return lay;
		}
		return null;
	},
	
	/**
     * Rimuove le features da un layer della mappa se vettoriale.
     * @param {OpenLayers.Layer} layer Layer OpenLayers WMS o Vector.
     */
	cleanLayer: function(layer){
		var lay = this.getLayer(layer);
		if(lay && lay instanceof OpenLayers.Layer.Vector && lay.features.length > 0){
			lay.destroyFeatures();
		}			
	},
	
	/**
     * Esegue una operazione di zoom usando l'extent fornito come argomento.
     * @param {Object} evt Oggetto contenente le proprietà di zoom.
	 * @param {OpenLayers.Bounds} [evt.dataExtent] Extent a cui eseguire lo zoom.
     */
	zoomToMapExtent: function(evt){
		if(evt.dataExtent){
			this.map.zoomToExtent(evt.dataExtent, false);
		}
	},
	
	/**
     * Disegna il box relativo alla selezione utente.
     * @param {Object} evt Oggetto contenente le proprietà relative alle operazioni da eseguire.
	 * @param {Object} [evt.scope] Scope su cui applicare le operazioni contenute.
     */
	onAfterBoxLayout: function(evt){
		var mgr = this;
		var map = this.map;
		var scope = evt.scope;
		var updatingNumbers = false;
		
        var link = Ext.get(scope.id+"_bboxAOI-set-EPSG");
        if(link){
          link.addListener("click", scope.openEPSGWin, scope);  
        }
        
		var baseProj = map.getProjection();
		var projection = baseProj ? baseProj : map.projection; 		
		
        scope.mapProjection = new OpenLayers.Projection(projection);
        
        var updateBoxDimension = function(field, newValue) {
        	if(!updatingNumbers){
        		
        		var left = this.westField.getValue();
        		var bottom = this.southField.getValue();
        		var right = this.eastField.getValue();
        		var top = this.northField.getValue();
        			
        		this.selectBBOX.updateBoxDimension(left,bottom,right,top);        		
        		var bounds = new OpenLayers.Bounds(left,bottom,right,top);
        		var geom = bounds.toGeometry();
                scope.ownerCt.setCurrentGeometry(geom);
                 
        	}
        }
        
        var updateCoordsFieldValue = function(bounds){
        	scope.northField.setValue(bounds.top);
            scope.southField.setValue(bounds.bottom);
            scope.westField.setValue(bounds.left);
            scope.eastField.setValue(bounds.right); 
        }
        
        var setCoordsReadOnly = function(readonly){
        	scope.northField.setReadOnly(readonly);
            scope.southField.setReadOnly(readonly);
            scope.westField.setReadOnly(readonly);
            scope.eastField.setReadOnly(readonly);
        }
        
        var activateMapExtentFiltering = function(){
        	scope.selectBBOX.deactivate();
			scope.bboxButton.disable();
			if(scope.bboxButton.pressed) {
				scope.bboxButton.toggle();
			}
			setCoordsReadOnly(true);
			updateCoordsFieldValue(mgr.map.getExtent());
			mgr.on("mapmoved", updateCoordsFieldValue);	
			updateBoxDimension.call(scope);
        }
        
        var deactivateMapExtentFiltering = function(){
        	mgr.un("mapmoved", updateCoordsFieldValue);
        	setCoordsReadOnly(false);
        	scope.bboxButton.enable();     
        	scope.selectBBOX.deactivate();
        	mgr.cleanLayer(scope.layerName);
        }
        
        scope.selectBBOX = new OpenLayers.Control.SetBox({      
            map: map,       
            layerName: scope.layerName,
            displayInLayerSwitcher: scope.displayBBOXInLayerSwitcher,
            boxDivClassName: "olHandlerBoxZoomBox_" + scope.id,
            aoiStyle: new OpenLayers.StyleMap({
				"default" : scope.defaultStyle,
				"select": scope.selectStyle,
				"temporary": scope.temporaryStyle
			}),
            onChangeAOI: function(){
            	updatingNumbers = true;
            	var bounds = new OpenLayers.Bounds.fromString(this.currentAOI);  
              
            	updateCoordsFieldValue(bounds); 
                
                this.deactivate();
                scope.bboxButton.toggle();
                
                var geom = bounds.toGeometry();
                scope.ownerCt.setCurrentGeometry(geom);
                updatingNumbers = false;                
            } 
        }); 
        
        var msDelay = 200;
        
        scope.northField.on('change',updateBoxDimension,scope,{delay: msDelay});
    	scope.southField.on('change',updateBoxDimension,scope,{delay: msDelay});
    	scope.westField.on('change',updateBoxDimension,scope,{delay: msDelay});
    	scope.eastField.on('change',updateBoxDimension,scope,{delay: msDelay});

        map.addControl(scope.selectBBOX);
        
        scope.on('mapExtentActive', activateMapExtentFiltering);
        scope.on('mapExtentDeactive',deactivateMapExtentFiltering);
        
        map.enebaleMapEvent = true;
	},
	
    /**
     * Aggiunge il conrollo di selezione delle coordinate sulla mappa.
	 * @param {Object} scope Scope su cui applicare le operazioni contenute.
     */
	addCoordinatePickerControl: function(scope){
		var map = this.map;
		
		if(scope && map){
			var compositeField = scope;
			scope.projectionObject = map.getProjectionObject();
			
	        //create the click control
	        var ClickControl = OpenLayers.Class(OpenLayers.Control, {                
	            defaultHandlerOptions: {
	                'single': true,
	                'double': false,
	                'pixelTolerance': 0,
	                'stopSingle': false,
	                'stopDouble': false
	            },

	            initialize: function(options) {
	                this.handlerOptions = OpenLayers.Util.extend(
	                    {}, this.defaultHandlerOptions
	                );
	                OpenLayers.Control.prototype.initialize.apply(
	                    this, arguments
	                ); 
	                this.handler = new OpenLayers.Handler.Click(
	                    compositeField, {
	                        'click': this.trigger
	                    }, this.handlerOptions
	                );
	            }, 
	            trigger: function(e){
	                //get lon lat
	                var lonlat = map.getLonLatFromPixel(e.xy);	                	                
	                var geoJsonPoint = lonlat.clone();	                	                	                
	                
	                /*  DECOMMENTARE SE SI VUOLE visualizzare le coordinate nel sistema di riferimento impostato per il buffer selector
	                 
		                var tPoint = new Point(lonlat.lon, lonlat.lat);
		                tPoint.transform(map.getProjectionObject().getCode(),scope.outputSRS);
		                
		                geoJsonPoint.lon = tPoint.x;
		                geoJsonPoint.lat = tPoint.y;
	                */
	                
	                scope.latitudeField.setValue(geoJsonPoint.lat);
	                scope.longitudeField.setValue(geoJsonPoint.lon);
	                
	                //update point on the map
	                scope.updateMapPoint(lonlat);
	                scope.toggleButton(false);
	            },
	            map: map
	        });       
	        
	        scope.selectLonLat = new ClickControl();
	        this.map.addControl(scope.selectLonLat);	
		}
	},
	
	/**
     * Aggiorna il punto sulla mappa a seguito di una selezione.
	 * @param {OpenLayers.LonLat} lonlat Coordinate relative al punto selezionato.
	 * @param {Object} scope Scope su cui applicare le operazioni contenute.
     */
	updateMapPoint: function(lonlat, scope){
		if(lonlat){
	        var style = new OpenLayers.Style(scope.selectStyle);
	        scope.layer = new OpenLayers.Layer.Vector(scope.selectLayerName, {
	            styleMap: style                
	        });
	        var point = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
	        var pointFeature = new OpenLayers.Feature.Vector(point);
	        scope.layer.addFeatures([pointFeature]);
	        scope.layer.displayInLayerSwitcher = scope.displayInLayerSwitcher;
	        this.map.addLayer(scope.layer);  
		}
	},
	
	/**
     * Disegna il buffer sulla mappa a seguito delle impostazioni utente.
	 * @param {OpenLayers.Geometry.Point} point Centro del poligono.
	 * @param {Boolean} geodesic Scope su cui applicare le operazioni contenute.
	 * @param {number} radius Raggio del poligono.
	 * @param {OpenLayers.Style} style Style con cui disegnare il buffer.
	 * @param {String} layername Il nome del layer.
	 * @param {Boolean} displayInLayerSwitcher Indica se mostrare il layers all'interno del layers switcher OpenLayers.
	 * @param {Function} callback Funzione di callback da invocare successivamente alle operazioni contenute.
	 * @param {Object} scope Scope su cui applicare le operazioni contenute.
     */
	drawBuffer: function(point, geodesic, radius, style, 
			layername, displayInLayerSwitcher, callback, scope){
		var regularPolygon;
		var map = this.map;
		
		if(geodesic){
			regularPolygon = OpenLayers.Geometry.Polygon.createGeodesicPolygon(
				point,
				radius,
				100, 
				0,
				map.getProjectionObject()
			);
			
		} else {
			
			var newRadius = radius;
			
			var geomUnits = this.map.getUnits();    
			var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[scope.distanceUnit];
			
			if(inPerDisplayUnit) {
				var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
				newRadius *= (inPerDisplayUnit/inPerMapUnit);
			}			 
			
			regularPolygon = OpenLayers.Geometry.Polygon.createRegularPolygon(
				point,
				newRadius,
				100, 
				0
			);
		}

		if(style){
			var layer = map.getLayersByName(layername)[0];
            if(layer){
                map.removeLayer(layer);
            }
                
            var style = new OpenLayers.Style(style);
            
			var bufferLayer = new OpenLayers.Layer.Vector(layername, {
                styleMap: style                
            });

            var bufferFeature = new OpenLayers.Feature.Vector(regularPolygon);
            bufferLayer.addFeatures([bufferFeature]);			
            bufferLayer.displayInLayerSwitcher = displayInLayerSwitcher;
            
            if(callback){
            	callback.call(scope ? scope : this, bufferLayer, bufferFeature);
            }
            
            map.addLayer(bufferLayer);  
        } 
	},
	
	/**
     * Attiva il controllo OpenLayers di selezione spaziale.
	 * @param {Object} scope Scope su cui applicare le operazioni contenute.
     */
	polygonSpatialSelectorActive: function(scope){
		/**
		 * Create Polygon Selector
		 */
		scope.drawings = new OpenLayers.Layer.Vector({},
			{
				displayInLayerSwitcher:false,
				styleMap : new OpenLayers.StyleMap({
					"default" : scope.defaultStyle,
					"select" : scope.selectStyle,
					"temporary" : scope.temporaryStyle
				})
			}
		);
			
		scope.persistance = new OpenLayers.Layer.Vector({},
			{
				displayInLayerSwitcher:false,
				styleMap : new OpenLayers.StyleMap({
					"default" : scope.defaultStyle,
					"select" : scope.selectStyle,
					"temporary" : scope.temporaryStyle
				})
			}
		);

		scope.drawings.events.on({
            "featureadded": function(event) {
            	scope.setCurrentGeometry(event.feature.geometry);
            	scope.persistance.addFeatures([event.feature]);
            	scope.freeze();
            },                                
            "beforefeatureadded": function(event) {
            	scope.drawings.destroyFeatures();
            },
            scope: scope
        });                                 
    
		// Aggiunge il layers di selezione spaziale alla mappa
		this.addLayer(scope.drawings);
		
		// Aggiunge il layer di visualizzazione definitiva
		this.addLayer(scope.persistance);
		
		scope.draw = scope.getDrawControl();
        
		// disable pan while drawing
		scope.draw.handler.stopDown = true;
		scope.draw.handler.stopUp = true;

		this.map.addControl(scope.draw);
		
        scope.draw.activate();
	},
	
	/**
     * Disattiva il controllo OpenLayers di selezione spaziale.
	 * @param {Object} scope Scope su cui applicare le operazioni contenute.
     */
	polygonSpatialSelectorDeactive: function(scope){
		if(scope.drawings){
			this.removeLayer(scope.drawings);
			scope.drawings = null;
		}
		if(scope.persistance){
			this.removeLayer(scope.persistance);
			scope.persistance = null;
		}
	},
	
	/**
     * Aggiorna le unità della mappa sul componente selezinato.
	 * @param {Object} component Componente su cui applicare le operazioni contenute.
     */
	setMapUnitsValueField: function(component){
		if(component){
			component.setValue(this.map.units);
		}
	}
	
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

Ext.ns('TolomeoExt.data');

/**
 * Un data store da usare come tool di autocompletamento paginato.
 * Non sono richiesti parametri di configurazione per il costruttore, il proxy
 * si appoggia alle canoniche funzionalità di TolomeoExt
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.data.ToloUniqueValuesStore', {
	
	extend: 'Ext.data.Store',
	
	alias: 'widget.tolomeo_uniquestore',

	/**
     * Crea un nuovo TolomeoExt.data.ToloUniqueValuesStore.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	constructor: function(config) {
        config.baseParams = Ext.apply(config.baseParams || {}, {});

        this.TOLOMEOServer =  config.TOLOMEOServer;
        this.TOLOMEOContext = config.TOLOMEOContext;
        
		var proxy = TolomeoExt.ToloCrossAjaxUtil.getProxy(null, this.TOLOMEOServer + this.TOLOMEOContext + '/UniqueValueServlet');
		var reader = proxy.getReader();
		reader.root = "rows";
		reader.totalProperty = "total";
		
        TolomeoExt.data.ToloUniqueValuesStore.superclass.constructor.call(this,
            Ext.applyIf(config, {
//                sortInfo: {
//                    field: 'value',
//                    direction: 'ASC'
//                },
                proxy: proxy
            })
        );
        
        this.pageSize = config.pageSize;
    },
	 
	/**
     * Imposta i parametri da passare al proxy per il caricamento dei dati.
     * @param {Object} params Un opzionale oggetto di configurazione per il componente ExtJs.
     */
    setParams: function(params) {
        this.baseParams = Ext.apply(this.baseParams, params);
    },
    
    /**
     * Carica i dati nello store.
     * @param {Object} options Oggetto contenente le opzioni di caricamento dei dati.
     */
    load: function(options) {
    	var count = this.getCount() > 0 && this.pageSize == 0;
     	if(!count){
        	var params = options.params;
            if (!params.inputs) {
                return;
            }
            
            var filter;
            params.query = params.query || "*";
            if(params.query) {
                var queryValue = params.query;
                if(queryValue.indexOf('*') === -1) {
                    queryValue = '*' + queryValue + '*';
                }
                
                filter = new OpenLayers.Filter.Comparison({ 
                    type: OpenLayers.Filter.Comparison.LIKE, 
                    property: params.inputs.fieldName, 
                    value: queryValue,
                    matchCase: false                
                });
                
                var node = new OpenLayers.Format.Filter({version: "1.1.0"}).write(filter);
                filter = new OpenLayers.Format.XML().write(node);
            }
            
    		var fparams = {
    			filter: filter,
    			codTPN: params.inputs.featureTypeName,
    			format: "ext",
    			ogcFilterVersion: "1.1.0",
    			attributeName: params.inputs.fieldName,
    			attributeLogicalName : params.inputs.attributeLogicalName 
    		};
    		
    		this.proxy.extraParams = this.proxy.extraParams || {};
    		this.proxy.startParam = "startIndex";
    		this.proxy.limitParam = "maxFeatures";
    		this.proxy.actionMethods = "POST";
    		
        	Ext.apply(this.proxy.extraParams, fparams); 
    		
            if (options) {
                this.baseParams = Ext.apply(this.baseParams, options.params);
            }
            
            this.superclass.load.call(this, options);
    	}
    } 
});

/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

// /////////////////////////////////////
// requires OpenLayers/Control.js
// requires OpenLayers/Handler/Box.js
// /////////////////////////////////////

/**
 * Controllo OpenLayers per la selezione del Box.
 * 
 * @extends {OpenLayers.Control}
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
OpenLayers.Control.SetBox = OpenLayers.Class(OpenLayers.Control, {

    /**
     * @cfg {OpenLayers.Control.TYPE} type [displayProjection="OpenLayers.Control.TYPE_TOOL"]
     * 
     */ 
    type: OpenLayers.Control.TYPE_TOOL,

    /**
     * @cfg {Boolean} out [out="false"]
     * 
     */ 
    out: false,
    
    /**
     * @cfg {Object} aoi [aoi="null"]
     * 
     */ 
    aoi: null,
    
    /**
     * @cfg {OpenLayers.Bounds} boxes [boxes="null"]
     * 
     */ 
    boxes: null,
    
    /**
     * @cfg {String} currentAOI
     * 
     */ 
    currentAOI: "",
    
    /**
     * @cfg {Function} onChangeAOI [onChangeAOI="null"]
     * 
     */ 
    onChangeAOI: null,
    
    /**
     * @cfg {String} layerName [layerName="AOI"]
     * 
     */ 
    layerName: "AOI",
    
    /**
     * @cfg {Object} aoiStyle [aoiStyle="null"]
     * 
     */ 
    aoiStyle: null,
    
    /**
     * @cfg {OpenLayers.Map} map
     * 
     */ 
    map: null,
    
    /**
     * @cfg {Boolean} displayInLayerSwitcher [displayInLayerSwitcher="false"]
     * 
     */ 
    displayInLayerSwitcher: false,

	/**
     * Disegna il BOX.
     * 
     */ 
    draw: function() {
       
        this.handler = new OpenLayers.Handler.Box(this,
        {
            done: this.setAOI
        }, 
        {
            boxDivClassName: this.boxDivClassName   
        },
        {
            keyMask: this.keyMask
        });
    },
    
    /**
     * Aggiorna il disegno del bbox
     * @param {Number} ascissa minima.
     * @param {Number} ordinata minima.
     * @param {Number} ascissa massima.
     * @param {Number} ordinata massima.
     * 
     */
    updateBoxDimension: function(xmin, ymin, xmax, ymax){
    	
    	if(this.aoi!=null){       
            this.boxes.removeFeatures(this.aoi);
        }
    	
    	var bounds;
    	
    	this.currentAOI = xmin + ',' + ymin + ',' + xmax + ',' + ymax;   
    	bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
    	
    	if(this.layerName){
            var x=this.map.getLayersByName(this.layerName);
            var index=null;
            if(x.length>0){
                index=this.map.getLayerIndex(x[0]);
                this.map.removeLayer(x[0]);
            }
            var me=this;
            this.boxes  = new OpenLayers.Layer.Vector( this.layerName,{
                displayInLayerSwitcher: me.displayInLayerSwitcher,
                styleMap: me.aoiStyle
            });
            this.aoi = new OpenLayers.Feature.Vector(bounds.toGeometry());
            this.boxes.addFeatures(this.aoi);
            this.map.addLayer(this.boxes);

            if(index){
                this.map.setLayerIndex(this.boxes,index);
            }
        }	
    },

	/**
     * Imposta la regione di interesse risultante dal disegno dell'utente sulla mappa.
     * @param {Object} la posizione del Box nella mappa.
     * 
     */
    setAOI: function (position) {
        var control;
      
        if(this.map.enebaleMapEvent)
            control = this.map.enebaleMapEvent;
        else
            control = false;
           
        if(control){                    
            
            var xmin, ymin, xmax, ymax;
            
            if (position instanceof OpenLayers.Bounds) {
                if (!this.out) {
                	
                    var minXY = this.map.getLonLatFromPixel(
                        new OpenLayers.Pixel(position.left, position.bottom));
                    var maxXY = this.map.getLonLatFromPixel(
                        new OpenLayers.Pixel(position.right, position.top));

                    xmin = minXY.lon;
                    ymin = minXY.lat;
                    xmax = maxXY.lon;
                    ymax = maxXY.lat;
                    
                } else {
                	
                    var pixWidth = Math.abs(position.right-position.left);
                    var pixHeight = Math.abs(position.top-position.bottom);
                    var zoomFactor = Math.min((this.map.size.h / pixHeight),
                        (this.map.size.w / pixWidth));
                    var extent = this.map.getExtent();
                    var center = this.map.getLonLatFromPixel(
                        position.getCenterPixel());
                    var xmin = center.lon - (extent.getWidth()/2)*zoomFactor;
                    var xmax = center.lon + (extent.getWidth()/2)*zoomFactor;
                    var ymin = center.lat - (extent.getHeight()/2)*zoomFactor;
                    var ymax = center.lat + (extent.getHeight()/2)*zoomFactor;
                    
                }

                this.updateBoxDimension(xmin, ymin, xmax, ymax);

                if(this.onChangeAOI)
                    this.onChangeAOI();
                   
            } else { 
                //
                // it's a pixel
                //
                if (!this.out) {
                    this.map.setCenter(this.map.getLonLatFromPixel(position),
                        this.map.getZoom() + 1);
                } else {
                    this.map.setCenter(this.map.getLonLatFromPixel(position),
                        this.map.getZoom() - 1);
                }
            }
        }      
    },

    CLASS_NAME: "OpenLayers.Control.SetBox"
    	
});
/*
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Rappresentazione di vertice per il routing
 * Può essere utilizzato come vertice iniziale, finale o intermedio.
 * 
 * @param street {string} nome della strada
 * @param point {JSGeometry} geometria
 * 
 * @property street {string} nome della strada
 * @property point {JSGeometry} geometria
 * 
 * @constructor
 */
function ToloOLSVertex(street, point, id)
{
	this.street = street;
	this.point = point;
	this.id = id;
}

/**
 * Modello dei dati generale per l'estensione OpenLS
 * 
 * @property geocodedAddresses {GeocodedAddress[]} array di indirizzi georiferiti
 * @property geometry {Point} geometria del punto di cui è richiesto il reverse geocoding
 * @property srsName {string} sistema di riferimento del punto di cui è richiesto il reverse geocoding
 * @property startPoint {ToloOLSVertex} vertice iniziale del routing
 * @property endPoint {ToloOLSVertex} vertice finale del routing
 * @property viaPoints {ToloOLSVertex[]} array di vertici intermedi del routing
 * @property method {string} metodo di routing
 * @property routeResponse {RouteResponse} risposta di routing
 * 
 * @constructor
 */
function ToloOLSModel()
{
	this.geocodedAddresses = null;
	this.geometry = null;
	this.srsname = null;
	this.startPoint = null;
	this.endPoint = null;
	this.viaPoints = [];
	this.viaPointId = 0;
	this.method = 'Fastest';
	this.routeResponse = null;
}

/**
 * Rappresentazione di una indirizzo georiferito
 * 
 * @param geometry {JSGeometry} geometria
 * @param postalCode {string} codice postale
 * @param address {Address} indirizzo
 * @param match {GeocodeMatch} tipo di match
 * 
 * @property geometry {JSGeometry} geometria
 * @property postalCode {string} codice postale
 * @property summary {Address} indirizzo
 * @property match {GeocodeMatch} tipo di match
 * 
 * @constructor
 */
function GeocodedAddress(geometry, srsName, postalCode, address, match)
{
 	this.geometry = geometry;
 	this.srsName = srsName;
 	this.postalCode = postalCode;
 	this.address = address;
 	this.match = match;
}

/**
 * Rappresentazione di un indirizzo
 * 
 * @param countryCode {string} codice nazione
 * @param streetAddress {StreetAddress} Indirizzo della strada
 * @param places {string[string]} luoghi
 * 
 * @property countryCode {string} codice nazione
 * @property streetAddress {StreetAddress} Indirizzo della strada
 * @property places {string[string]} luoghi
 * 
 * @constructor
 */
function Address(countryCode, streetAddress, places)
{
 	this.countryCode = countryCode;
 	this.streetAddress = streetAddress;
 	this.places = places;
}

/**
 * Rappresentazione di un indirizzo di una strada
 * 
 * @param street {string} Indirizzo della strada
 * 
 * @property street {string} Indirizzo della strada
 * 
 * @constructor
 */
function StreetAddress(street)
{
 	this.street = street;
}

/**
 * Rappresentazione di un match
 * 
 * @param accuracy {string} indice di accuratezza
 * @param type {string} tipo di match
 * 
 * @property accuracy {string} indice di accuratezza
 * @property type {string} tipo di match
 * 
 * @constructor
 */
function GeocodeMatch(accuracy, type)
{
 	this.accuracy = accuracy;
 	this.type = type;
}

/**
 * Rappresentazione di una risposta di routing
 * 
 * @param summary {RouteSummary} sommario del routing
 * @param geometry {JSGeometry} geometria
 * @param instructions {RouteInstruction[]} array di istruzioni di routing
 * 
 * @property summary {RouteSummary} sommario del routing
 * @property geometry {JSGeometry} geometria
 * @property instructions {RouteInstruction[]} array di istruzioni di routing
 * 
 * @constructor
 */
function RouteResponse(summary, geometry, instructions)
{
 	this.summary = summary;
 	this.geometry = geometry;
 	this.instructions = instructions;
}

/**
 * Rappresentazione delle informazioni di sintesi di una risposta di routing
 * 
 * @param totalTime {string} durata
 * @param totalDistance {TotalDistance} distanza totale
 * @param boundingBox {BBox} bounding box del routing
 * 
 * @property totalTime {string} durata
 * @property totalDistance {TotalDistance} distanza totale
 * @property boundingBox {BBox} bounding box del routing
 * 
 * @constructor
 */
function RouteSummary(totalTime, totalDistance, boundingBox)
{
 	this.totalTime = totalTime;
 	this.totalDistance = totalDistance;
 	this.boundingBox = boundingBox;
}

/**
 * Rappresentazione della distanza percorsa da un routing
 * 
 * @param value {number} distanza
 * @param uom {string} unità di misura
 * @param accuracy {number} accuratezza percentuale
 * 
 * @property value {number} distanza
 * @property uom {string} unità di misura
 * @property accuracy {number} accuratezza percentuale
 * 
 * @constructor
 */
function TotalDistance(value, uom, accuracy)
{
 	this.value = value;
 	this.uom = uom;
 	this.accuracy = accuracy;
}

/**
 * Rappresentazione di una istruzione di routing
 * 
 * @param instruction {string} istruzioni di routing
 * @param distance {number} distanza del singolo lag
 * @param geometry {JSGeometry} geoemtria del lag
 * 
 * @property instruction {string} istruzioni di routing
 * @property distance {number} distanza del singolo lag
 * @property geometry {JSGeometry} geoemtria del lag
 * 
 * @constructor
 */
function RouteInstruction(instruction, textInstruction, distance, geometry)
{
 	this.instruction = instruction;
 	this.textInstruction = textInstruction;
 	this.distance = distance;
 	this.geometry = geometry;
 	this.instructionId = Math.random(); 
}
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.OLS.BaseForm
 * Form base
 * @author Ugo Paternostro <br/>phoops s.r.l.
 */
Ext.define('TolomeoExt.OLS.BaseForm', {
	extend: 'Ext.form.FormPanel',
	
	/** 
	 * Property: srid
	 * {} sistema di riferimento in cui sono espresse le coordinate
	 */
	srid: null,
	
	/** 
	 * Property: url
	 * {} URL dove è esposto il server OpenLS
	 */
    url: 'http://localhost/geoserver/ols',
	
	/** 
	 * Property: username
	 * {} utente per l'autenticazione OpenLS
	 */
	username: null,
	
	/** 
	 * Property: password
	 * {} password per l'autenticazione OpenLS
	 */
	password: null,
	
	/** 
	 * Property: useProxyServlet
	 * {} forza l'utilizzo della TolomeoProxyServlet
	 */
	useProxyServlet: false,
	
	/** 
	 * Property: TOLOMEOContext
	 * {String}
	 */
	TOLOMEOContext: null,
	
    initComponent:function() {
    	var config = 
    	{
		    xlsNamespace:	'http://www.opengis.net/xls',
		    gmlNamespace:	'http://www.opengis.net/gml',
		    xlsVersion:		'1.2',
		    
		    submitRequest: function(method, requestId, xmlBuilderCallback, successCallback) {
		    	var	me = this;
		    	
	        	document.body.style.cursor = "wait";
	        	
		   		var xmlhttp = null;
				
		   		if (window.XMLHttpRequest) {
		    		// code for IE7+, Firefox, Chrome, Opera, Safari
		   			xmlhttp = new XMLHttpRequest();
		   		} else {
		    		// code for IE6, IE5
		   			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		   		}
		   		
		   		var url = this.url;
		   		
		   		if (this.useProxyServlet) {
		   			url = this.TOLOMEOContext + "/TolomeoProxyServlet?" + this.url;
		   		}
		   		
		   		// Handle POST request
		   		xmlhttp.open("POST", url);
		   		
		   		xmlhttp.onreadystatechange = function() {
		   			if (xmlhttp.readyState == 4)
		   			{
		   			    switch (xmlhttp.status)
		   			    {
			   			    case 200:
			   			    	if (xmlhttp.responseXML != null) {
				   			    	// Check the workspace error;
				   			    	var errorMess = xmlhttp.responseXML.toString();
				   			    	
				   			    	if (errorMess != "noWorkspace") {
							        	// lvl 0
							        	var xls = xmlhttp.responseXML.firstChild;

							        	if (xls != null && xls.localName == 'XLS' && xls.namespaceURI == me.xlsNamespace) {
								        	// lvl 1
								        	var responseList = xls.getElementsByTagNameNS(me.xlsNamespace, "Response");
								        	
								        	if (responseList != null && responseList.length == 1) {
							   			    	successCallback.call(me, responseList.item(0));
								        	} else {
									    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noResponse.title"), ToloI18n.getMsg("BaseForm.err.noResponse.msg"));
								        	}
							        	} else {
								    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noXLS.title"), ToloI18n.getMsg("BaseForm.err.noXLS.msg"));
							        	}
				   			    	} else {
				   			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noWKS.title"), ToloI18n.getMsg("BaseForm.err.noWKS.msg"));
				   			    	}
			   			    	} else {
			   			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noWKS.title"), ToloI18n.getMsg("BaseForm.err.noWKS.msg"));
			   			    	}
			   			        break;
						    case 401:
						    	Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noAuth.title"), ToloI18n.getMsg("BaseForm.err.noAuth.msg"));
						        break;
						    case 404:
						    	Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noService.title"), ToloI18n.getMsg("BaseForm.err.noService.msg"));
						        break;
						    case 500:
						    	var dlg = new Ext.window.MessageBox({autoScroll: true}).show({
						    		title: ToloI18n.getMsg("BaseForm.err.server.title"), 
						    		msg: ToloI18n.getMsg("BaseForm.err.server.msg", {method : method }),
						    		buttons: Ext.Msg.YESNO,
						    	    icon: Ext.Msg.ERROR,
						    	    fn: function(btn) {
						    	        if (btn === 'yes') {
									    	new Ext.window.MessageBox({autoScroll: true}).alert(ToloI18n.getMsg("BaseForm.err.server.title"), xmlhttp.responseText);
						    	        } 
						    	    }
						    	});
						    	dlg.defaultButton = 2;
						    	break;
						    default:
						    	Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.generico.title"), ToloI18n.getMsg("BaseForm.err.generico.msg", {xmlhttpstatus: xmlhttp.status, xmlhttpresponseText: xmlhttp.responseText}));
						    	break;
		   			    }
		   			    
				    	document.body.style.cursor = "default";
		   			}    
		   	    };
		   	    
		   	    var dom = this.createEmptyXMLDoc('XLS xmlns="' + this.xlsNamespace + '"');
				var root = dom.documentElement;
				root.setAttribute("version",	this.xlsVersion);
				var header = dom.createElementNS(this.xlsNamespace, 'RequestHeader');
				header.setAttribute("srsName",	this.srid);
				if (this.username != null && this.username != "") {
					header.setAttribute("clientName", this.username);
				}
				if (this.password != null && this.password != "") {
					header.setAttribute("clientPassword", this.password);
				}
				root.appendChild(header);
				var request = dom.createElementNS(this.xlsNamespace, 'Request');
				request.setAttribute("methodName",	method);
				request.setAttribute("version",		this.xlsVersion);
				request.setAttribute("requestID",	requestId);
				root.appendChild(request);
				
				xmlBuilderCallback.call(me, dom, request);
				
		   	    xmlhttp.send(dom);
		   	},
		   	createEmptyXMLDoc: function(root)
		   	{
		   		var xmlDoc;
		   		
		   		if (window.DOMParser) {
			   		parser=new DOMParser();
			   		xmlDoc=parser.parseFromString("<" + root + "/>", "text/xml");
		   		} else {
		   			// Internet Explorer
			   		xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
			   		xmlDoc.async="false";
			   		xmlDoc.loadXML("<" + root + "/>");
		   		}
		   		
		   		return xmlDoc;
		   	},
	        buildPosition: function(dom, pointObj, srsName)
	        {
	        	var	position = dom.createElementNS(this.xlsNamespace, 'Position');
	        	var	point = dom.createElementNS(this.gmlNamespace, 'Point');
	        	var	pos = dom.createElementNS(this.gmlNamespace, 'pos');
	        	pos.setAttribute("srsName", srsName)
	        	var	posValue = dom.createTextNode(pointObj.x + " " + pointObj.y);
	        	pos.appendChild(posValue);
	        	point.appendChild(pos);
	        	position.appendChild(point);
	        	
	        	return position;
	        },
	        parseGeocodedAddresses: function(geocodedAddressList, isMatchCodeMandatory)
	        {
	        	var geocodedAddresses = [];
	        	
	        	for (var i = 0; i < geocodedAddressList.length; i++) {
	        		var item = geocodedAddressList.item(i);
	        		
		        	// lvl 5
		        	var pointList = item.getElementsByTagNameNS(this.gmlNamespace, "Point");
		        	
		        	if (pointList == null || pointList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.nopoint.title"), ToloI18n.getMsg("BaseForm.err.nopoint.msg"));
		        		return;
		        	}
	        		
		        	var postalCodeList = item.getElementsByTagNameNS(this.xlsNamespace, "PostalCode");
		        	
//		        	if (postalCodeList == null || postalCodeList.length != 1) {
//			    		Ext.MessageBox.alert('Error', 'No PostalCode found in geocoding response!');
//		        		return;
//		        	}
		        	
		        	var addressList = item.getElementsByTagNameNS(this.xlsNamespace, "Address");
		        	
		        	if (addressList == null || addressList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noaddress.title"), ToloI18n.getMsg("BaseForm.err.noaddress.msg"));
		        		return;
		        	}
		        	
		        	var address = addressList.item(0);
	        		
		        	var gmcList = item.getElementsByTagNameNS(this.xlsNamespace, "GeocodeMatchCode");
		        	
		        	if (gmcList == null || (isMatchCodeMandatory && gmcList.length != 1)) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.nogeomatch.title"), ToloI18n.getMsg("BaseForm.err.nogeomatch.msg"));
		        		return;
		        	}
	        		
		        	var gmc = gmcList.item(0);
	        		
		        	// lvl 6
		        	var posList = pointList.item(0).getElementsByTagNameNS(this.gmlNamespace, "pos");
		        	
		        	if (posList == null || posList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.nopos.title"), ToloI18n.getMsg("BaseForm.err.nopos.msg"));
		        		return;
		        	}
		        	
		        	var pos = posList.item(0);
	        		
		        	var streetAddressList = address.getElementsByTagNameNS(this.xlsNamespace, "StreetAddress");
		        	
		        	if (streetAddressList == null || streetAddressList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noStreetAddr.title"), ToloI18n.getMsg("BaseForm.err.noStreetAddr.msg"));
		        		return;
		        	}
	        		
		        	var placeList = address.getElementsByTagNameNS(this.xlsNamespace, "Place");
		        	
		        	if (placeList == null || placeList.length < 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noPlace.title"), ToloI18n.getMsg("BaseForm.err.noPlace.msg"));
		        		return;
		        	}
	        		
		        	// lvl 7
		        	var streetList = streetAddressList.item(0).getElementsByTagNameNS(this.xlsNamespace, "Street");
		        	
		        	if (streetList == null || streetList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("BaseForm.err.noStreet.title"), ToloI18n.getMsg("BaseForm.err.noStreet.msg"));
		        		return;
		        	}
	        		
		        	// let's rock
	        		var position = pos.firstChild.nodeValue.split(" ");
	        		var postalCode = "";
	        		var places = {};
	        		
	        		if (postalCodeList != null && postalCodeList.length == 1) {
	        			postalCode = postalCodeList.item(0).firstChild.nodeValue;
	        		}
	        		
	        		for (var j = 0; j < placeList.length; j++) {
	        			var place = placeList.item(j);
	        			
	        			places[place.getAttribute("type")] = place.firstChild.nodeValue;
	        		}
	        		
	        		geocodedAddresses.push(
		        		new GeocodedAddress(
			        			new Point(
			        				position[0],
			        				position[1]
			        			),
			        			pos.getAttribute("srsName"),
			        			postalCode,
			        			new Address(
			        					address.getAttribute("countryCode"),
			        				new StreetAddress(
			        					streetList.item(0).firstChild.nodeValue
			        				),
			        				places
			        			),
			        			gmc == null ? null : new GeocodeMatch(
			        				gmc.getAttribute("accuracy"),
			        				gmc.getAttribute("type")
			        			)
			        		)
	        		);
	        	}
	        	
	        	return geocodedAddresses;
	        }
    	};
    	
    	Ext.apply(this, Ext.apply(this.initialConfig, config));
		this.callParent();
    }
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.OLS.GeocodingForm
 * Form di geocoding
 * @author Ugo Paternostro <br/>phoops s.r.l.
 */
Ext.define('TolomeoExt.OLS.GeocodingForm', {
	extend: 'TolomeoExt.OLS.BaseForm',
	
	itemId: 'olsGeocodingID',
	collapsible: true,
	
    initComponent:function() {
		// Eventi
    	this.addEvents('dataReceived');
		
    	var config = 
    	{
		        labelWidth:		75, // label settings here cascade unless 	
		        frame:			true,
		        title:			'Ricerca indirizzo',
		        bodyStyle:		'padding:5px 5px 0',
		        cls:			'floating-form_left',
		        height:			150,
		        defaults: {
		        	width:		230
		        },
		        defaultType:	'textfield',
		        
		        items: [
		          {
		        	  xtype: 'combo',
		        	  store: new Ext.data.ArrayStore({
		        	        fields: [
		        	            'abbr',
		        	            'prov'
		        	        ],
		        	        data: [ ['AR', 'Arezzo - AR'], // @@@ FIXME!
		        	                ['FI', 'Firenze - FI'],
		        	                ['GR', 'Grosseto - GR'],
		        	                ['LI', 'Livorno - LI'],
		        	                ['LU', 'Lucca - LU'],
		        	                ['MS', 'Massa-Carrara - MS'],
		        	                ['PI', 'Pisa - PI'],
		        	                ['PT', 'Pistoia - PT'],
		        	                ['PO', 'Prato - PO'],
		        	                ['SI', 'Siena - SI']
		        	        	 ]
		        	    }),
		        	  valueField: 'abbr',
			          displayField: 'prov',
			          typeAhead: true,
			          mode: 'local',
			          forceSelection: true,
			          triggerAction: 'all',
			          emptyText:ToloI18n.getMsg("GeocodingForm.cmbProv.emptyText"),
			          selectOnFocus:true,
		        	  fieldLabel: ToloI18n.getMsg("GeocodingForm.cmbProv.lbl"),
		        	  itemId: 'provincia'
		          },
		          {
		        	  fieldLabel: ToloI18n.getMsg("GeocodingForm.fldComune"),	    	   
		        	  itemId: 'comune',
		        	  listeners: {
			              scope: this,
		                  specialkey: function(f, e) {
		                    if (e.getKey() == e.ENTER) {
		                    	this.submit();
		                    }
		                  }
		              }
		          },
		          {
		        	  fieldLabel: ToloI18n.getMsg("GeocodingForm.fldTopo"),
		        	  itemId: 'via',
		        	  listeners: {
			              scope: this,
		                  specialkey: function(f, e) {
		                    if (e.getKey() == e.ENTER) {
		                    	this.submit();
		                    }
		                  }
		              },
		        	  validator: function(v) {
		        		  if (v === "" || v == null || v.lenght == 0) {
		        		        return ToloI18n.getMsg("GeocodingForm.fldTopo.invalid");
		        		  }
		        		  
		        		  return true;
		        	  }
		          }
		        ],
		        buttons: [
		            {
		            	text: ToloI18n.getMsg("GeocodingForm.btnTrova"),
		            	scope: this,
		            	handler: function(toponimo) {
			        	  this.submit();
		            	}
		            },
		            {
		            	text: ToloI18n.getMsg("GeocodingForm.btnPulisci"),
		            	scope: this,
		            	handler: function(){
		            		this.items.get('provincia').setValue(null);
		            		this.items.get('comune').setValue(null);
		            		this.items.get('via').setValue(null);
			            }	
		            }
		        ],
		        submit: function() {
		        	if (this.items.get('provincia').isValid()
		        			&& this.items.get('comune').isValid()
		        			&& this.items.get('via').isValid()) {
		        		this.submitRequest("GeocodeRequest", "GRid", this.buildXMLRequest, this.onSuccess);
		        	}
		        },
		        buildXMLRequest: function(dom, request)
		        {
		        	var	geocodeRequest = dom.createElementNS(this.xlsNamespace, 'GeocodeRequest');
		        	var	address = dom.createElementNS(this.xlsNamespace, 'Address');
		        	address.setAttribute("countryCode", "IT");
		        	var	streetAddress = dom.createElementNS(this.xlsNamespace, 'StreetAddress');
		        	var	street = dom.createElementNS(this.xlsNamespace, 'Street');
		        	var	streetName = dom.createTextNode(this.items.get('via').getValue());
		        	street.appendChild(streetName);
		        	streetAddress.appendChild(street);
		        	address.appendChild(streetAddress);
		        	var	municipality = dom.createElementNS(this.xlsNamespace, 'Place');
		        	municipality.setAttribute("type", "Municipality");
		        	var	municipalityName = dom.createTextNode(this.items.get('comune').getValue());
		        	municipality.appendChild(municipalityName);
		        	address.appendChild(municipality);
		        	var	countrySecondarySubdivision = dom.createElementNS(this.xlsNamespace, 'Place');
		        	countrySecondarySubdivision.setAttribute("type", "CountrySecondarySubdivision");
		        	var	countrySecondarySubdivisionName = dom.createTextNode(this.items.get('provincia').getValue());
		        	countrySecondarySubdivision.appendChild(countrySecondarySubdivisionName);
		        	address.appendChild(countrySecondarySubdivision);
		        	var	postalCode = dom.createElementNS(this.xlsNamespace, 'PostalCode');
		        	address.appendChild(postalCode);
		        	geocodeRequest.appendChild(address);
		        	request.appendChild(geocodeRequest);
		        },
		        onSuccess: function(response)
		        {
		        	// lvl 2
		        	var grList = response.getElementsByTagNameNS(this.xlsNamespace, "GeocodeResponse");
		        	
		        	if (grList == null || grList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("GeocodingForm.indirizzoNonTrovato.title"),ToloI18n.getMsg("GeocodingForm.indirizzoNonTrovato.msg"));
		        		return;
		        	}
		        	
		        	// lvl 3
		        	var grlList = grList.item(0).getElementsByTagNameNS(this.xlsNamespace, "GeocodeResponseList");
		        	
		        	if (grlList == null || grlList.length != 1) {
		        		Ext.MessageBox.alert(("GeocodingForm.indirizzoNonTrovato.title"),ToloI18n.getMsg("GeocodingForm.indirizzoNonTrovato.msg"));
		        		return;
		        	}
		        	
		        	// lvl 4
		        	var geocodedAddressList = grlList.item(0).getElementsByTagNameNS(this.xlsNamespace, "GeocodedAddress");
		        	
		        	if (geocodedAddressList == null || geocodedAddressList.length < 1) {
		        		Ext.MessageBox.alert(("GeocodingForm.indirizzoNonTrovato.title"),ToloI18n.getMsg("GeocodingForm.indirizzoNonTrovato.msg"));
		        		return;
		        	}
		        	
   			    	this.fireEvent('dataReceived', response.getAttribute("requestID"), this.parseGeocodedAddresses(geocodedAddressList, true));
		        }
    	};
    	
    	Ext.apply(this, Ext.apply(this.initialConfig, config));
		this.callParent();
    }
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.OLS.ReverseGeocodingForm
 * Form di reverse geocoding
 * @author Ugo Paternostro <br/>phoops s.r.l.
 */
Ext.define('TolomeoExt.OLS.GeocodingListPanel', {
	extend: 'Ext.grid.GridPanel',
	
    itemId:	"streetsList",
    
	/** 
	 * Property: iconBasePath
	 * 
	 */
	iconBasePath: null,
	
	/** 
	 * Property: model
	 * 
	 */
	model: null,
	
    initComponent:function() {
    	this.addEvents('addressSelected');
    	this.addEvents('addressFocus');
    	this.addEvents('addressBlur');
    	this.addEvents('startAddressSelected');
    	this.addEvents('endAddressSelected');
    	this.addEvents('viaAddressSelected');
    	
        var config = {
        		frame:true,
            	stripeRows: true,
//                autoExpandColumn: 'street',
                height: 240,
               // title: 'Open LS Results',
                // config options for stateful behavior
                stateful: true,
                bodyStyle:'padding:5px',
                cls: 'floating-form_right',

                singleSelect : true,
                reserveScrollOffset: true,

                store: new Ext.data.ArrayStore({
                    fields: [
                       {name: 'street', convert: function(value, record) {
                           return record.raw.address.streetAddress.street;
                       }},
                       {name: 'postalcode', convert: function(value, record) {
                           return record.raw.postalCode;
                       }},
                       {name: 'place', convert: function(value, record) {
                           return record.raw.address.places['Municipality'];
                       }},
                       {name: 'secondarysubdivision', convert: function(value, record) {
                           return record.raw.address.places['CountrySecondarySubdivision'];
                       }},
                       {name: 'subdivision', convert: function(value, record) {
                           return record.raw.address.places['CountrySubdivision'];
                       }},
                       {name: 'country', convert: function(value, record) {
                           return record.raw.address.countryCode;
                       }}
                    ]
                }),
                refreshData: function(){
                    this.store.loadData(this.model.geocodedAddresses);
                },
        		viewConfig: {
	    			//firstCls: null,
	    			trackOver: true
	    		},
	    		listeners: {
        			'itemmouseenter':	{
        									fn: function(record, item, index, e) { 
						        				this.fireEvent('addressFocus', item); 
						        			},
						        			scope: this
						    			},
        			'itemmouseleave':	{
        									fn: function(record, item, index, e) { 
						        				this.fireEvent('addressBlur', item); 
						        			},
						        			scope: this
						    			},
        			'itemclick':		{
        									fn: function(obj, record, item, index, e) {
        										// Evitiamo di far partire due eventi nel caso di click su un'icona di un action column
        										if (e.getTarget().className.indexOf("action-col") == -1) {
        											this.fireEvent('addressSelected', record);
        										}
						        			},
						        			scope: this
					        			}
	    		},
                        columns: [
                                {
                              	  	menuDisabled: true,
                                    xtype: 'actioncolumn',
                                    width: 25,
                                    items: [{
                                        icon   : this.iconBasePath + 'ols/MapMarker.png',
                                        tooltip: 'Zoom into map',
                                        scope: this,
                                        handler: function(view, rowIndex, colIndex, item, e, record, row) {
                           			        this.fireEvent('addressSelected', record);
                                        }
                                    }]
                                },
                                  {
                                      id       :'street',
                                      header   : ToloI18n.getMsg("GeocodingListPanel.colStrada"),
                                      width    : 220,
                                      sortable : true,
                                      dataIndex: 'street'
                                  },
                                  {
                                      header   : ToloI18n.getMsg("GeocodingListPanel.colCAP"),
                                      width    : 40,
                                      sortable : true,
                                      dataIndex: 'postalcode'
                                  },
                                  {
                                      header   : ToloI18n.getMsg("GeocodingListPanel.colLuogo"),
                                      width    : 150,
                                      sortable : true,
                                      dataIndex: 'place'
                                  },
                                  {
                                      header   : ToloI18n.getMsg("GeocodingListPanel.colProvincia"),
                                      width    : 80,
                                      sortable : true,
                                      dataIndex: 'secondarysubdivision'
                                  },
                                  {
                                      header   : ToloI18n.getMsg("GeocodingListPanel.colRegione"),
                                      width    : 80,
                                      sortable : true,
                                      dataIndex: 'subdivision'
                                  },
                                  {
                                      header   : ToloI18n.getMsg("GeocodingListPanel.colNazione"),
                                      width    : 50,
                                      sortable : true,
                                      dataIndex: 'country'
                                  },
                                  {
                               	  	  menuDisabled: true,
                                      xtype: 'actioncolumn',
                                      width: 30,
                                      sortable : false,
                                      items: [{
                                          icon   : this.iconBasePath + 'ols/start.png',
                                          tooltip: ToloI18n.getMsg("GeocodingListPanel.Partenza"),
                                          scope: this,
                                          handler: function(view, rowIndex, colIndex, item, e, record, row) {
                             			      this.fireEvent('startAddressSelected', record);
                                          }
                                      }]
                                  },
                                  {
                               	  	  menuDisabled: true,
                                      xtype: 'actioncolumn',
                                      width: 30,
                                      sortable : false,
                                      items: [{
                                          icon   : this.iconBasePath + 'ols/via.png',
                                          tooltip: ToloI18n.getMsg("GeocodingListPanel.Arrivo"),
                                          scope: this,
                                          handler: function(view, rowIndex, colIndex, item, e, record, row) {
                             			      this.fireEvent('viaAddressSelected', record);
                                          }
                                      }]
                                  },
                                  {
                               	  	  menuDisabled: true,
                                      xtype: 'actioncolumn',
                                      width: 30,
                                      sortable : false,
                                      items: [{
                                          icon   : this.iconBasePath + 'ols/stop.png',
                                          tooltip: ToloI18n.getMsg("GeocodingListPanel.Interm"),
                                          scope: this,
                                          handler: function(view, rowIndex, colIndex, item, e, record, row) {
                             			      this.fireEvent('endAddressSelected', record);
                                          }
                                      }]
                                  }
                                  
                              ]
        };
    	
    	Ext.apply(this, Ext.apply(this.initialConfig, config));
		this.callParent();
    }
});/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.OLS.NavigationListPanel
 * Pannello per le istruzioni di navigazione
 * @author Ugo Paternostro <br/>phoops s.r.l.
 */
Ext.define('TolomeoExt.OLS.NavigationListPanel', {
	extend: 'Ext.grid.GridPanel',
	
    itemId:	"navigationList",
    
	/** 
	 * Property: model
	 * 
	 */
	model: null,
    
    initComponent:function() {
    	this.addEvents('navigationSelected');
    	this.addEvents('navigationFocus');
    	this.addEvents('navigationBlur');
    	
        var config = {
        		//frame:true,
//            	stripeRows: true,
//                autoExpandColumn: 'street',
//            	width: '78%',
//            	width: '22%',
                height: 185,
               // title: 'Navigation Information',
                // config options for stateful behavior
                stateful: true,
//                bodyStyle:'padding:5px 5px 0',
//                cls: 'floating-form_left',
                store: new Ext.data.ArrayStore({
                    fields: [
                             {name: 'navigation', convert: function(value, record) {
                                 return record.raw.instruction;
                             }},
                             {name: 'instructionId', convert: function(value, record) {
                                 return record.raw.instructionId;
                             }}]
                      }),
                singleSelect : true,
                header: false,
//                reserveScrollOffset: true,
                refreshData: function()
                {
                	this.store.loadData(this.model.routeResponse.instructions);
                },
	    		listeners: {
        			'itemmouseenter':	{
        									fn: function(thisgrid, record, item, index, e) { 
						        				this.fireEvent('navigationFocus', index); 
						        			},
						        			scope: this
						    			},
        			'itemmouseleave':	{
        									fn: function(thisgrid, record, item, index, e) { 
						        				this.fireEvent('navigationBlur', index); 
						        			},
						        			scope: this
						    			},
        			'itemclick':		{
        									fn: function(thisgrid, record, item, index, e) { 
						        				this.fireEvent('navigationSelected', index); 
						        			},
						        			scope: this
					        			} 
	    		},
                columns: [
                         {
                              itemId   :'navigation',
                      //        header   : 'Navigation Info',
                              width    : '100%',
                              sortable : false,
                              dataIndex: 'navigation'
                          }
                      ]
        };
    	
    	Ext.apply(this, Ext.apply(this.initialConfig, config));
		this.callParent();
    },
    
    routingInformationSelect: function(instructionId) {
    	var idx = this.store.find('instructionId', instructionId);
    	this.getSelectionModel().select(idx);
	}, 
	
	routingInformationDeSelect: function(instructionId) {
		var idx = this.store.find('instructionId', instructionId);
		this.getSelectionModel().deselect(idx);
	}
    
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.OLS.ReverseGeocodingForm
 * Form di reverse geocoding
 * @author Ugo Paternostro <br/>phoops s.r.l.
 */
Ext.define('TolomeoExt.OLS.ReverseGeocodingForm', {
	extend: 'TolomeoExt.OLS.BaseForm',
	
	itemId: 'olsReverseGeocodingID',
	collapsible: true,
	
	pointObj: null,
	srsName: null,
	
	initComponent:function() {
		// Eventi
    	this.addEvents('dataReceived');
		
		var config = {
				itemId: 'formReverseId',
		        labelWidth: 75, // label settings here cascade unless 	
		        frame:true,
		        collapsed:true,
		        title: ToloI18n.getMsg("ReverseGeocodingForm.title"),
		        bodyStyle:'padding:5px 5px 0',
//		        width: '22%',
		        cls: 'floating-form_left',
		        height: 100,
		        defaults: {width: 230},
		        defaultType: 'textfield',	
		        
		        items: [
				          {
				        	  fieldLabel: ToloI18n.getMsg("ReverseGeocodingForm.lat"),
				        	  itemId: 'lat',
				        	  disabled: true
				          },
				          {
				        	  fieldLabel: ToloI18n.getMsg("ReverseGeocodingForm.lon"),
				        	  itemId: 'lon',
				        	  disabled : true
				          }
				        ],
				        
		        submit: function(requestId) {
	        		this.submitRequest("ReverseGeocodeRequest", requestId, this.buildXMLRequest, this.onSuccess);
		        },
		        buildXMLRequest: function(dom, request)
		        {
		        	var	reverseGeocodeRequest = dom.createElementNS(this.xlsNamespace, 'ReverseGeocodeRequest');
		        	var	position = this.buildPosition(dom, this.pointObj, this.srsName);
		        	reverseGeocodeRequest.appendChild(position);
		        	request.appendChild(reverseGeocodeRequest);
		        },
		        onSuccess: function(response)
		        {
		        	// lvl 2
		        	var rgrList = response.getElementsByTagNameNS(this.xlsNamespace, "ReverseGeocodeResponse");
		        	
		        	if (rgrList == null || rgrList.length != 1) {
		        		//Ext.MessageBox.alert('Informazione', 'Nessun indirizzo trovato vicino a questa posizione');
		        		this.fireEvent('dataReceived', response.getAttribute("requestID"), []);
		        		return;
		        	}
		        	
		        	// lvl 3
		        	var rglList = rgrList.item(0).getElementsByTagNameNS(this.xlsNamespace, "ReverseGeocodedLocation");
		        	
		        	if (rglList == null || rglList.length < 1) {
		        		//Ext.MessageBox.alert('Informazione', 'Nessun indirizzo trovato vicino a questa posizione');
		        		this.fireEvent('dataReceived', response.getAttribute("requestID"), []);
		        		return;
		        	}
		        	
   			    	this.fireEvent('dataReceived', response.getAttribute("requestID"), this.parseGeocodedAddresses(rglList, false));
		        },
		        reverseGeocode: function(requestId, geometry, srsName)
		        {
		        	this.pointObj = geometry;
		        	this.srsName = srsName;
		        	this.submit(requestId);
		        }
    	};
    	
		Ext.apply(this, Ext.apply(this.initialConfig, config));
		this.callParent();
	}
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.OLS.NavigationListPanel
 * Pannello per le istruzioni di navigazione
 * @author Alessandro Radaelli
 */
Ext.define('TolomeoExt.OLS.NavigationSummaryPanel', {
	extend: 'Ext.Panel',
	
	/** 
	 * Property: model
	 * 
	 */
	model: null,
    
    initComponent:function() {
    	    	
        var config = {
                height: 70,
                title: 'Sommario', 
                collapsible: true,
                collapsed: false,
                bodyStyle:'padding:5px 5px 0'
//                cls: 'floating-form_left',
        };
    	
    	Ext.apply(this, Ext.apply(this.initialConfig, config));
		this.callParent();
		
    },
    
    refreshData: function() {
    	
    	var totalTime 		= "";
    	var totalDistance 	= "";
    	
    	if (this.model && this.model.routeResponse && this.model.routeResponse.summary) {
    		totalTime = this.model.routeResponse.summary.totalTime;
        	totalDistance = this.model.routeResponse.summary.totalDistance;
    	}
    	
    	var regExp =  /PT(\d*H)?(\d*M)?(\d*\.)(\d*S)/;
    	var time = regExp.exec(totalTime);
    	
    	var ore = time[1] ? time[1].substring(0,time[1].length-1) + "h " : ""; 
    	var minuti = time[2] ? time[2].substring(0,time[2].length-1) + "m " : "";
    	var secondi = time[3] ? time[3].substring(0,time[3].length-1) + "s " : "";
    	
    	this.update(ToloI18n.getMsg("NavigationSummaryPanel.navtime", {tempo: ore + minuti + secondi, dist:Ext.util.Format.number(totalDistance.value, '0.00'), um: totalDistance.uom }));
    }

});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.OLS.RoutingNavigationForm
 * Form di geocoding
 * @author Ugo Paternostro <br/>phoops s.r.l.
 */
Ext.define('TolomeoExt.OLS.RoutingNavigationForm', {
	extend: 'TolomeoExt.OLS.BaseForm',
	
	itemId: 'olsRoutingNavigationID',
	collapsible: true,
	
	/** 
	 * Property: model
	 * 
	 */
	model: null,
	
    initComponent:function() {
    	this.addEvents('methodChanged');
    	this.addEvents('reset');
    	this.addEvents('routeReceived');
    	
    	var config = 
    	{
		        labelWidth: 75, // label settings here cascade unless 	
		        frame:true,
		        //title: 'Routing Navigation',
		        bodyStyle:'padding:5px 5px 0',
//		        width: '22%',
		        cls: 'floating-form_left',
		        height: 200,
		        defaults: {
		        	width: 230
		        },
//		        defaultType: 'textfield',
		    	instructionFormat: "text/html",
		    	
		        items: [
		          {
		        	  xtype: 'textfield',
		        	  fieldLabel: ToloI18n.getMsg("RoutingNavigationForm.partenza"),
		        	  itemId: 'startPoint',
		        	  disabled: true,
		        	  handler: function(storeData){
		        		  	var store = storeData.toString();
		        		  	var values=store.split(",");
				        	this.setValue(values[0]);
		        	  },
		        	  validator: function(v) {
		        		  if (v == null || v === "" || v.lenght == 0) {
		        		        return ToloI18n.getMsg("RoutingNavigationForm.partenza.noncorr");
		        		    }
		        		    return true;
                      }
		          },
		          {
		        	  xtype: 'textfield',
		        	  fieldLabel: ToloI18n.getMsg("RoutingNavigationForm.arrivo"),
		        	  itemId: 'endPoint',
		        	  disabled: true,
		        	  handler: function(storeData){
		        		  	var store = storeData.toString();
		        		  	var values=store.split(",");
				        	this.setValue(values[0]);
		        	  },
		        	  validator: function(v) {
		        		  if (v == null || v === "" || v.lenght == 0) {
		        		        return ToloI18n.getMsg("RoutingNavigationForm.arrivo.noncorr");
		        		    }
		        		    return true;
                      }
		          },
		          {
		        	  xtype: 'combo',
		        	  store: new Ext.data.ArrayStore({
		        	        id: 0,
		        	        fields: [
		        	            'method'
		        	        ],
		        	        data: [ [ToloI18n.getMsg("RoutingNavigationForm.veloce")],
		        	                [ToloI18n.getMsg("RoutingNavigationForm.corto")],
		        	                [ToloI18n.getMsg("RoutingNavigationForm.metodo.pedoni")]
		        	        	 ]
		        	    }),
			          displayField: 'method',
			          typeAhead: true,
			          mode: 'local',
			          forceSelection: true,
			          triggerAction: 'all',
			          value: 'Fastest',
//			          emptyText:'Seleziona un Metodo...',
			          selectOnFocus:true,
		        	  fieldLabel: 'Method',
		        	  itemId: 'method',
		        	  listeners: {
		        		  scope: this,
			        	  select: function(combo, records, eOpts) {
			        		  this.fireEvent('methodChanged', records[0].raw);
			        	  }
		        	  }
		          },
		          {
		        	  	xtype:'label',
	                    text: ToloI18n.getMsg("RoutingNavigationForm.info"),
	                    name: 'infoLabel',
	                    labelStyle: 'font-weight:bold;',
	                    anchor:'93%'	    	   
		          }
		        ],
		        buttons: [
		            {
		            	text: ToloI18n.getMsg("RoutingNavigationForm.btnInvia"),
		            	scope: this,
		            	handler: function(toponimo){
	                    	this.submit();
		            	}
		            },
		            {	
		            	text: ToloI18n.getMsg("RoutingNavigationForm.btnPulisci"),
		            	scope: this,
		            	handler: function(){
			        		this.fireEvent('reset', 'dummy');
			            }	
		            }
		        ],
		        submit: function() {
		        	if (this.model.startPoint != null
		        			&& this.model.endPoint != null
		        			&& this.items.get('method').isValid()) {
		        		this.submitRequest("DetermineRouteRequest", "RRid", this.buildXMLRequest, this.onSuccess);
		        	}
		        },
		        buildXMLRequest: function(dom, request)
		        {
		        	var	determineRouteRequest = dom.createElementNS(this.xlsNamespace, 'DetermineRouteRequest');
		        	var	routePlan = dom.createElementNS(this.xlsNamespace, 'RoutePlan');
		        	var	routePreference = dom.createElementNS(this.xlsNamespace, 'RoutePreference');
		        	var	routePreferenceValue = dom.createTextNode(this.model.method);
		        	routePreference.appendChild(routePreferenceValue);
		        	routePlan.appendChild(routePreference);
		        	var	wayPointList = dom.createElementNS(this.xlsNamespace, 'WayPointList');
		        	
		        	// start point
		        	var	startPoint = dom.createElementNS(this.xlsNamespace, 'StartPoint');
		        	var	startPosition = this.buildPosition(dom, this.model.startPoint.point, this.srid);
		        	startPoint.appendChild(startPosition);
		        	wayPointList.appendChild(startPoint);
		        	
		        	// VIAs
            		for(var i = 0; i < this.model.viaPoints.length; i++) {
    		        	var	viaPoint = dom.createElementNS(this.xlsNamespace, 'ViaPoint');
    		        	var	viaPosition = this.buildPosition(dom, this.model.viaPoints[i].point, this.srid);
    		        	viaPoint.appendChild(viaPosition);
    		        	wayPointList.appendChild(viaPoint);
            		}
            		
            		// end point
		        	var	endPoint = dom.createElementNS(this.xlsNamespace, 'EndPoint');
		        	var	endPosition = this.buildPosition(dom, this.model.endPoint.point, this.srid);
		        	endPoint.appendChild(endPosition);
		        	wayPointList.appendChild(endPoint);
		        	routePlan.appendChild(wayPointList);
		        	determineRouteRequest.appendChild(routePlan);
		        	
		        	var	routeInstructionsRequest = dom.createElementNS(this.xlsNamespace, 'RouteInstructionsRequest');
		        	routeInstructionsRequest.setAttribute("format", this.instructionFormat);
		        	routeInstructionsRequest.setAttribute("provideGeometry", "false");
		        	determineRouteRequest.appendChild(routeInstructionsRequest);
		        	
		        	request.appendChild(determineRouteRequest);
		        },
		        onSuccess: function(response)
		        {
		        	// lvl 2
		        	var drrList = response.getElementsByTagNameNS(this.xlsNamespace, "DetermineRouteResponse");
		        	
		        	if (drrList == null || drrList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noDetRoute.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noDetRoute.msg"));
		        		return;
		        	}
		        	
		        	var drr = drrList.item(0);
		        	
		        	// lvl 3
		        	var summaryList = drr.getElementsByTagNameNS(this.xlsNamespace, "RouteSummary");
		        	
		        	if (summaryList == null || summaryList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noRouteSumm.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noRouteSumm.msg"));
		        		return;
		        	}
		        	
		        	var geometryList = drr.getElementsByTagNameNS(this.xlsNamespace, "RouteGeometry");
		        	
		        	if (geometryList == null || geometryList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noRouteGeom.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noRouteGeom.msg"));
		        		return;
		        	}
		        	
		        	var instructionsListList = drr.getElementsByTagNameNS(this.xlsNamespace, "RouteInstructionsList");
		        	
		        	if (instructionsListList == null || instructionsListList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noRouteInstList.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noRouteInstList.msg"));
		        		return;
		        	}
		        	
		        	var summary = summaryList.item(0);
		        	
		        	// lvl 4
		        	var totalTimeList = summary.getElementsByTagNameNS(this.xlsNamespace, "TotalTime");
		        	
		        	if (totalTimeList == null || totalTimeList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noTotalTime.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noTotalTime.msg"));
		        		return;
		        	}
		        	
		        	var totalDistanceList = summary.getElementsByTagNameNS(this.xlsNamespace, "TotalDistance");
		        	
		        	if (totalDistanceList == null || totalDistanceList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noTotalDist.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noTotalDist.msg"));
		        		return;
		        	}
		        	
		        	var boundingBoxList = summary.getElementsByTagNameNS(this.xlsNamespace, "BoundingBox");
		        	
		        	if (boundingBoxList == null || boundingBoxList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noBBOX.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noBBOX.msg"));
		        		return;
		        	}
		        	
		        	var lineStringList = geometryList.item(0).getElementsByTagNameNS(this.gmlNamespace, "LineString");
		        	
		        	if (lineStringList == null || lineStringList.length != 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noLineStr.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noLineStr.msg"));
		        		return;
		        	}
		        	
		        	var instructionsList = instructionsListList.item(0).getElementsByTagNameNS(this.xlsNamespace, "RouteInstruction");
		        	
		        	if (instructionsList == null || instructionsList.length < 1) {
			    		Ext.MessageBox.alert(ToloI18n.getMsg("RoutingNavigationForm.err.noRouteInst.title"),ToloI18n.getMsg("RoutingNavigationForm.err.noRouteInst.msg"));
		        		return;
		        	}
		        	
		        	// let's rock ;)
		        	var distanceAttributes = totalDistanceList.item(0).attributes;
		        	var routeGeometry = this.createLineString(lineStringList.item(0));
		        	var instructions = [];
		        	
		        	for (var i = 0; i < instructionsList.length; i++) {
		        		instructions.push(this.createRoutingInstruction(instructionsList.item(i)));
		        	}
		        	
		        	var routeResponse = new RouteResponse(
	        			new RouteSummary(
    	        			totalTimeList.item(0).firstChild.nodeValue,
    	        			new TotalDistance(
        		        		distanceAttributes.getNamedItem("value").nodeValue,
        		        		distanceAttributes.getNamedItem("uom").nodeValue,
        		        		distanceAttributes.getNamedItem("accuracy").nodeValue
        		        	),
    	        			this.createBoundingBox(boundingBoxList.item(0))
    	        		),
    	        		routeGeometry,
    	        		instructions
		        	);
		        	
   			    	this.fireEvent('routeReceived', response.getAttribute("requestID"), routeResponse);
		        },
		        createBoundingBox: function(xml)
		        {
	        		var posList = xml.getElementsByTagNameNS(this.gmlNamespace, "pos");
	        		var bottomLeftCoords = posList.item(0).firstChild.nodeValue.split(" ");
	        		var topRightCoords = posList.item(1).firstChild.nodeValue.split(" ");
	        		
	        		return new BBox(bottomLeftCoords[1], bottomLeftCoords[0], topRightCoords[1], topRightCoords[0]);
		        },
		        createLineString: function(xml)
		        {
		        	var routeWKT = "LINESTRING(";
        			var posList = xml.getElementsByTagNameNS(this.gmlNamespace, "pos");
        			
        			for (var i = 0; i < posList.length; i++) {
    	        		var itemPos = posList.item(i);
        				
        				if (i == posList.length - 1) {
        					routeWKT += itemPos.firstChild.nodeValue;
        				} else {
        					routeWKT += itemPos.firstChild.nodeValue + ",";
        				}
        			}
        			
        			routeWKT += ")";
        			
					return new JSGeometry(null, null, "OLS route", routeWKT, null, xml.attributes.getNamedItem("srsName").nodeValue, null);
		        },
		        createRoutingInstruction: function(xml)
		        {
		        	// lvl 1
        			var instructionList = xml.getElementsByTagNameNS(this.xlsNamespace, "Instruction");
        			var distanceList = xml.getElementsByTagNameNS(this.xlsNamespace, "distance");
        			var geometryList = xml.getElementsByTagNameNS(this.xlsNamespace, "RouteInstructionGeometry");
        			
        			// lvl 2
        			var lineStringList = geometryList.item(0).getElementsByTagNameNS(this.gmlNamespace, "LineString");
        			
        			var instruction = instructionList.item(0).firstChild.nodeValue;
        			var textInstruction;
        			
        			switch (this.instructionFormat) {
        				case "text/plain":
        					textInstruction = instruction;
        					break;
        				case "text/html":
        					textInstruction = instruction.replace(/<[^>]*>/g, ' ').trim();
        					break;
        			}
        			
        			return new RouteInstruction(
        				instruction,
        				textInstruction,
            			distanceList.item(0).attributes.getNamedItem('value').nodeValue,
            			this.createLineString(lineStringList.item(0))
        			);
		        },
		        changeStartAddress: function() {
		        	this.items.get('startPoint').setValue(this.model.startPoint == null ? "" : this.model.startPoint.street);
		        },
		        changeEndAddress: function() {
		        	this.items.get('endPoint').setValue(this.model.endPoint == null ? "" : this.model.endPoint.street);
		        },
		        changeViaAddresses: function() {
		        	// do nothing at the moment
		        },
		        changeMethod: function() {
		        	this.items.get('method').setValue(this.model.method);
		        }
    	};
    	
    	Ext.apply(this, Ext.apply(this.initialConfig, config));
		this.callParent();
    }
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * Class: TolomeoExt.OLS.ViaListPanel
 * Pannello per le tappe intermedie
 * @author Ugo Paternostro <br/>phoops s.r.l.
 * 
 */
Ext.define('TolomeoExt.OLS.ViaListPanel', {
	extend: 'Ext.grid.GridPanel',
	
	itemId: "viaPointList",
	
	/** 
	 * Property: iconBasePath
	 * 
	 */
	iconBasePath: null,
	
	/** 
	 * Property: model
	 * 
	 */
	model: null,
	
	initComponent: function() {
		// Eventi
    	this.addEvents('viaPointFocus');
    	this.addEvents('viaPointBlur');
    	this.addEvents('viaPointSelected');
    	this.addEvents('deleteViaPoint');
    	this.addEvents('moveViaPoint');
    	
		var config = {
				collapsible: true,
			    requires: [
			               'Ext.grid.RowNumberer'
			           ],
			  // frame: true,
				stripeRows: true,
//				width: '30%',
				height: 240,
				title: ToloI18n.getMsg("ViaListPanel.title"),
				// config options for stateful behavior
                stateful: true,
                bodyStyle:'padding:5px',
              //  cls: 'floating-form_right',
                store: new Ext.data.ArrayStore({
                    fields: [
                             {name: 'stopAt', convert: function(value, record) {
                                 return record.raw.street;
                             }}
                          ],
                    data: this.model.viaPoints
                      }),
                singleSelect : true,
            //    autoScroll: true,
                //reserveScrollOffset: true,
	    		listeners: {
        			'itemmouseenter':	{
        									fn: function(record, item, index, e) { 
						        				this.fireEvent('viaPointFocus', item); 
						        			},
						        			scope: this
						    			},
        			'itemmouseleave':	{
        									fn: function(record, item, index, e) { 
						        				this.fireEvent('viaPointBlur', item); 
						        			},
						        			scope: this
						    			},
        			'itemclick':		{
        									fn: function(record, item, index, e) { 
						        				this.fireEvent('viaPointSelected', item); 
						        			},
						        			scope: this
					        			}
	    		},
        		columns: [
                          {
                        	  xtype: 'rownumberer'
                          }, 
                           {
                        	  menuDisabled: true,
                               itemId       :'stopAt',
                              // header   : 'Stop At',
                               width    : 160,
                               sortable : false,
                               dataIndex: 'stopAt'
                           },
                           {
                        	   menuDisabled: true,
                               xtype: 'actioncolumn',
                               width: 30,
                               sortable : false,
                               items: [{
                                   icon   : this.iconBasePath + 'elimina.gif',
                                   tooltip: ToloI18n.getMsg("ViaListPanel.elimina"),
                                   scope: this,
                                   handler: function(view, recordIndex, cellIndex, item, e, record, row)
                                   {
                                	   this.fireEvent('deleteViaPoint', recordIndex);
                                   }
                               }]
                           },
                           {
                        	   menuDisabled: true,
                        	   xtype: 'actioncolumn',
                               width: 30,
                               sortable : false,
                               items: [{
                                   icon   : this.iconBasePath + 'ols/top.png',
                                   tooltip: ToloI18n.getMsg("ViaListPanel.su"),
                                   isDisabled: function(view, rowIndex, colIndex, item, record)
                                   {
                                	   return rowIndex == 0;
                                   },
                                   scope: this,
                                   handler: function(view, recordIndex, cellIndex, item, e, record, row)
                                   {
                                	   this.fireEvent('moveViaPoint', recordIndex, -1);
                                   }
                               }]
                           },
                           {
                        	   menuDisabled: true,
                        	   xtype: 'actioncolumn',
                               width: 30,
                               sortable : false,
                               items: [{
                                   icon   : this.iconBasePath + 'ols/down.png',
                                   tooltip: ToloI18n.getMsg("ViaListPanel.giu"),
                                   isDisabled: function(view, rowIndex, colIndex, item, record)
                                   {
                                	   return rowIndex == record.store.data.length - 1;
                                   },
                                   scope: this,
                                   handler: function(view, recordIndex, cellIndex, item, e, record, row)
                                   {
                                	   this.fireEvent('moveViaPoint', recordIndex, +1);
                                   }
                               }]
                           }
                          ],
            changeViaAddresses: function()
            {
            	this.store.loadData(this.model.viaPoints);
            }
		};
		
    	Ext.apply(this, Ext.apply(this.initialConfig, config));
		this.callParent();
	}
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/

/**
 * Class: TolomeoExt.ToloOLSPanelExt
 * Funzioni pubbliche di geocoding/reversegeocoding/routing & navigation
 * @author Ugo Paternostro <br/>phoops s.r.l.
 */
Ext.define('TolomeoExt.OLS.ToloOLSPanelExt', {

	extend: 'Ext.Panel',
	//requires: [],


	/** 
	 * Property: paramsJS
	 * {JSONObject}
	 */
	paramsJS: null,

	/** 
	 * Property: TOLOMEOServer
	 * {String}
	 */
	TOLOMEOServer: null,

	/** 
	 * Property: TOLOMEOContext
	 * {String}
	 */
	TOLOMEOContext: null,
	
	/** 
	 * Property: iconBasePath
	 * 
	 */
	iconBasePath: null,
	
	/** 
	 * Property: model
	 * 
	 */
	model: null,
	
	/** 
	 * Property: pnlGeocoding
	 * {}
	 */
	pnlGeocoding: null,

	/** 
	 * Property: pnlGeocodingList
	 * {}
	 */
	pnlGeocodingList: null,
	
	/** 
	 * Property: wndGeocodingList
	 * {}
	 */
	wndGeocodingList: null,
	
	/** 
	 * Property: pnlReverseGeocoding
	 * {}
	 */
	pnlReverseGeocoding: null,

	/** 
	 * Property: pnlReverseGeocoding
	 * {}
	 */
	pnlRoutingNavigation: null,

	/** 
	 * Property: pnlNavigationSummary
	 * {}
	 */
	pnlNavigationSummary: null,
	
	/** 
	 * Property: pnlNavigationList
	 * {}
	 */
	pnlNavigationList: null,

	/** 
	 * Property: wndNavigationList
	 * {}
	 */
	wndNavigationList: null,

	/** 
	 * Property: pnlViaList
	 * {}
	 */
	pnlViaList: null,

	/**
	 * Constructor: TolomeoExt.ToloOLSPanelExt
	 * Crea un nuovo TolomeoExt.ToloOLSPanelExt
	 *
	 * Returns:
	 * {<TolomeoExt.ToloOLSPanelExt>} Un nuovo TolomeoExt.ToloOLSPanelExt
	 */
	initComponent: function() {
    	this.addEvents('geocodingDataReceived');
    	this.addEvents('reverseGeocodingDataReceived');
    	this.addEvents('addressFocus');
    	this.addEvents('addressBlur');
    	this.addEvents('addressSelected');
    	this.addEvents('startAddressSelected');
    	this.addEvents('endAddressSelected');
    	this.addEvents('viaAddressAdded');
    	this.addEvents('reset');
    	this.addEvents('methodChanged');
    	this.addEvents('routeReceived');
    	this.addEvents('navigationFocus');
    	this.addEvents('navigationBlur');
    	this.addEvents('navigationSelected');
    	this.addEvents('viaPointFocus');
    	this.addEvents('viaPointBlur');
    	this.addEvents('viaPointSelected');
    	this.addEvents('viaPointsChanged');
    	
    	// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		this.layout = {
						type: 'vbox',
						align: 'stretch'
		};
		
		this.on('activate', this.focusFirstField);
		
		if (this.iconBasePath==null) this.iconBasePath =  TolomeoExt.Vars.TOLOMEOServer + TolomeoExt.Vars.TOLOMEOStaticRoot + 'img/icone/16-default/';
		
		this.model = new ToloOLSModel();
		
		if (this.paramsJS.layOut.ols.conGeocoding) {
			this.pnlGeocoding = Ext.create('TolomeoExt.OLS.GeocodingForm', {
				srid: this.paramsJS.mappe.SRID,
			    url: this.paramsJS.layOut.ols.url,
				username: this.paramsJS.layOut.ols.username,
				password: this.paramsJS.layOut.ols.password,
			    useProxyServlet: this.paramsJS.layOut.ols.useProxyServlet,
			    TOLOMEOContext: this.TOLOMEOContext
			});			
		}
		
		this.pnlGeocodingList = Ext.create('TolomeoExt.OLS.GeocodingListPanel', {
			iconBasePath: this.iconBasePath,
			model: this.model
		});
		
		this.wndGeocodingList = Ext.create('Ext.window.Window', {
			title: ToloI18n.getMsg("ToloOLSPanelExt.wndNavigationList"),
			layout: 'fit',
			height: 400,
			width: 800,
			maximizable: true,
			closeAction: 'hide',
			items: [this.pnlGeocodingList]}); 
	
		
		this.pnlReverseGeocoding = Ext.create('TolomeoExt.OLS.ReverseGeocodingForm', {
		    url: this.paramsJS.layOut.ols.url,
			username: this.paramsJS.layOut.ols.username,
			password: this.paramsJS.layOut.ols.password,
		    useProxyServlet: this.paramsJS.layOut.ols.useProxyServlet,
		    TOLOMEOContext: this.TOLOMEOContext
		});
		
		this.pnlRoutingNavigation = Ext.create('TolomeoExt.OLS.RoutingNavigationForm', {
			srid: this.paramsJS.mappe.SRID,
		    url: this.paramsJS.layOut.ols.url,
			username: this.paramsJS.layOut.ols.username,
			password: this.paramsJS.layOut.ols.password,
		    useProxyServlet: this.paramsJS.layOut.ols.useProxyServlet,
		    TOLOMEOContext: this.TOLOMEOContext,
			model: this.model
		});
		
		this.pnlNavigationList = Ext.create('TolomeoExt.OLS.NavigationListPanel', {
			model: this.model, 
			flex: 1
		});
		
		this.pnlNavigationSummary = Ext.create('TolomeoExt.OLS.NavigationSummaryPanel', {
			model: this.model
		}); 
		
		this.wndNavigationList = Ext.create('Ext.window.Window', {
			title: "Dati navigazione",
			//layout: 'fit',
			layout: {
				type: 'vbox',
				align: 'stretch'
			},
			height: 400,
			width: 500,
			maximizable: true,
			closeAction: 'hide',
			items: [this.pnlNavigationSummary, this.pnlNavigationList]}); 
		
		
		this.pnlViaList = Ext.create('TolomeoExt.OLS.ViaListPanel', {
			iconBasePath: this.iconBasePath,
			model: this.model,
			flex: 1
		});
		
		this.callParent();
		
		if (this.pnlGeocoding) {
			this.add(this.pnlGeocoding);
			
			this.pnlGeocoding.on('dataReceived', this.olsGeocodingDataReceivedHandler, this);
			   
	    	this.pnlGeocodingList.on('addressFocus', this.addressFocusHandler, this);
	    	this.pnlGeocodingList.on('addressBlur', this.addressBlurHandler, this);
	    	this.pnlGeocodingList.on('addressSelected', this.addressSelectedHandler, this);
	    	this.pnlGeocodingList.on('startAddressSelected', this.startAddressSelectedHandler, this);
	    	this.pnlGeocodingList.on('endAddressSelected', this.endAddressSelectedHandler, this);
	    	this.pnlGeocodingList.on('viaAddressSelected', this.viaAddressSelectedHandler, this);

		}
    	
		this.add(this.pnlViaList);
		
    	this.pnlReverseGeocoding.on('dataReceived', this.olsReverseGeocodingDataReceivedHandler, this);

    	this.pnlRoutingNavigation.on('methodChanged', this.methodChangedHandler, this);
    	this.pnlRoutingNavigation.on('reset', this.resetHandler, this);
    	this.pnlRoutingNavigation.on('routeReceived', this.routeReceivedHandler, this);

    	this.pnlNavigationList.on('navigationFocus', this.navigationFocusHandler, this);
    	this.pnlNavigationList.on('navigationBlur', this.navigationBlurHandler, this);
    	this.pnlNavigationList.on('navigationSelected', this.navigationSelectedHandler, this);
    	
    	this.pnlViaList.on('viaPointFocus', this.viaPointFocusHandler, this);
    	this.pnlViaList.on('viaPointBlur', this.viaPointBlurHandler, this);
    	this.pnlViaList.on('viaPointSelected', this.viaPointSelectedHandler, this);
    	this.pnlViaList.on('deleteViaPoint', this.deleteViaPointHandler, this);
    	this.pnlViaList.on('moveViaPoint', this.moveViaPointHandler, this);
    },
    
    // metodi privati
	
	// handler
	focusFirstField:function() {
		if ( this.pnlGeocoding && this.pnlGeocoding.items && this.pnlGeocoding.items.items.size>0) this.pnlGeocoding.items.items[0].focus(false, 30); 	
	},	
	olsGeocodingDataReceivedHandler: function(requestId, geocodedAddresses) {
		this.model.geocodedAddresses = geocodedAddresses;
		
		// Da spostare nella vista quando si fara' la separazione View-Controller
	    this.pnlGeocodingList.refreshData();
	    this.wndGeocodingList.show();
	    
    	this.fireEvent('geocodingDataReceived', geocodedAddresses);
	},
	olsReverseGeocodingDataReceivedHandler: function(requestId, geocodedAddresses) {
		if (requestId == "RGRid:USERPOINT") {
			if (geocodedAddresses.length>0) {
				this.model.geocodedAddresses = geocodedAddresses;
				
				// Da spostare nella vista quando si fara' la separazione View-Controller
			    this.pnlGeocodingList.refreshData();
			    this.wndGeocodingList.show();
			} else {
				Ext.MessageBox.alert(ToloI18n.getMsg("ToloOLSPanelExt.nessunind.title"),ToloI18n.getMsg("ToloOLSPanelExt.nessunind.msg"));
        		return;
			}
			
	    	this.fireEvent('reverseGeocodingDataReceived', geocodedAddresses);
		} else if (requestId == "RGRid:STARTPOINT") {
			if (geocodedAddresses.length>0) {
				this.model.startPoint.street = geocodedAddresses[0].address.streetAddress.street;
				this.pnlRoutingNavigation.changeStartAddress();
			}
		} else if (requestId == "RGRid:ENDPOINT") {
			if (geocodedAddresses.length>0) {
				this.model.endPoint.street = geocodedAddresses[0].address.streetAddress.street;
				this.pnlRoutingNavigation.changeEndAddress();
			}
		} else {
			// richiesta relativa ad un VIA point: id della forma RGRid:VIAPOINT:number
			var idArray = requestId.split(":");
			
			for (var i = 0; i < this.model.viaPoints.length; i++) {
				if (this.model.viaPoints[i].id == idArray[2]) {
					if (geocodedAddresses.length>0) {
						this.model.viaPoints[i].street = geocodedAddresses[0].address.streetAddress.street;
					} else {
						this.model.viaPoints[i].street = ToloI18n.getMsg("ToloOLSPanelExt.intermediocoord", {x: this.model.viaPoints[i].point.x.toFixed(4), y: this.model.viaPoints[i].point.y.toFixed(4)});
					}	
					this.pnlViaList.changeViaAddresses();
					break;
				}
			}
		}
	},
	addressFocusHandler: function(record) {
        var street = record.raw.address.streetAddress.street;
        var geometry = record.raw.geometry;
		
    	this.fireEvent('addressFocus', street, geometry.x, geometry.y, record.raw.srsName);
	},
	addressBlurHandler: function(record) {
        var street = record.raw.address.streetAddress.street;
        var geometry = record.raw.geometry;
		
    	this.fireEvent('addressBlur', street, geometry.x, geometry.y, record.raw.srsName);
	},
	addressSelectedHandler: function(record) {
        var street = record.raw.address.streetAddress.street;
        var geometry = record.raw.geometry;
		
    	this.fireEvent('addressSelected', street, geometry.x, geometry.y, record.raw.srsName, this.paramsJS.layOut.ols.zoomLevel);
	},
	startAddressSelectedHandler: function(record) {
        var street = record.raw.address.streetAddress.street;
        var geometry = record.raw.geometry;
        var srsName = record.raw.srsName;

        this.setStartAddress(geometry, srsName, street);
    	this.fireEvent('startAddressSelected', street, geometry.x, geometry.y, srsName, this.paramsJS.layOut.ols.zoomLevel);
	},
	endAddressSelectedHandler: function(record) {
        var street = record.raw.address.streetAddress.street;
        var geometry = record.raw.geometry;
        var srsName = record.raw.srsName;
		
        this.setEndAddress(geometry, srsName, street);
    	this.fireEvent('endAddressSelected', street, geometry.x, geometry.y, srsName, this.paramsJS.layOut.ols.zoomLevel);
	},
	viaAddressSelectedHandler: function(record) {
        var street = record.raw.address.streetAddress.street;
        var geometry = record.raw.geometry;
        var srsName = record.raw.srsName;
        var viaId = this.addViaAddress(geometry, srsName, street);
        
    	this.fireEvent('viaAddressAdded', viaId, street, geometry.x, geometry.y, srsName, this.paramsJS.layOut.ols.zoomLevel);
	},
	methodChangedHandler: function(method) {
		this.model.method = method;
		this.pnlRoutingNavigation.submit();
		
    	this.fireEvent('methodChanged', method);
	},
	resetHandler: function() {
		this.reset();
		
    	this.fireEvent('reset');
	},
	routeReceivedHandler: function(requestId, routeResponse) {
		this.model.routeResponse = routeResponse;
		
		// Da spostare nella vista quando si fara' la separazione View-Controller
	    this.wndGeocodingList.close();
	    this.pnlNavigationList.refreshData();
	    this.pnlNavigationSummary.refreshData();
	    this.wndNavigationList.show();
	    
    	this.fireEvent('routeReceived', routeResponse);
	},
	navigationFocusHandler: function(index) {
		var instruction = this.model.routeResponse.instructions[index]
		
    	this.fireEvent('navigationFocus', instruction, this.paramsJS.mappe.SRID);
	},
	navigationBlurHandler: function(index) {
		var instruction = this.model.routeResponse.instructions[index]
		
    	this.fireEvent('navigationBlur', instruction, this.paramsJS.mappe.SRID);
	},
	navigationSelectedHandler: function(index) {
		var instruction = this.model.routeResponse.instructions[index]
		
    	this.fireEvent('navigationSelected', instruction, this.paramsJS.mappe.SRID, this.paramsJS.layOut.ols.zoomLevel);
	},
	viaPointFocusHandler: function(record) {
        var geometry = record.raw.point;
		
    	this.fireEvent('viaPointFocus', record.raw.id, record.raw.street, geometry.x, geometry.y, this.paramsJS.mappe.SRID);
	},
	viaPointBlurHandler: function(record) {
        var geometry = record.raw.point;
		
    	this.fireEvent('viaPointBlur', record.raw.id, record.raw.street, geometry.x, geometry.y, this.paramsJS.mappe.SRID);
	},
	viaPointSelectedHandler: function(record) {
        var geometry = record.raw.point;
		
    	this.fireEvent('viaPointSelected', record.raw.id, record.raw.street, geometry.x, geometry.y, this.paramsJS.mappe.SRID, this.paramsJS.layOut.ols.zoomLevel);
	},
	deleteViaPointHandler: function(index) {
		this.model.viaPoints.splice(index, 1);
		
		// Da spostare nella vista quando si fara' la separazione View-Controller
    	this.pnlRoutingNavigation.changeViaAddresses();
        this.pnlViaList.changeViaAddresses();
		
		this.pnlRoutingNavigation.submit();
		
    	this.fireEvent('viaPointsChanged', this.model.viaPoints);
	},
	moveViaPointHandler: function(index, delta) {
		var via = this.model.viaPoints[index];
		this.model.viaPoints[index] = this.model.viaPoints[index+delta];
		this.model.viaPoints[index+delta] = via;
		
		// Da spostare nella vista quando si fara' la separazione View-Controller
    	this.pnlRoutingNavigation.changeViaAddresses();
        this.pnlViaList.changeViaAddresses();
		
		this.pnlRoutingNavigation.submit();
		
    	this.fireEvent('viaPointsChanged', this.model.viaPoints);
	},
	
	// metodi pubblici
	reverseGeocode: function(geometry, srsName) {
    	this.pnlReverseGeocoding.reverseGeocode("RGRid:USERPOINT", geometry, srsName);
    },
    setStartAddress: function(geometry, srsName, street) {
    	this.model.startPoint = new ToloOLSVertex(
    		street || ToloI18n.getMsg("ToloOLSPanelExt.setStartAddress.partenza"),
    		geometry.clone()
    	);
    	
    	if (this.paramsJS.mappe.SRID != srsName) {
	    	this.model.startPoint.point.transform(srsName, this.paramsJS.mappe.SRID);
    	}
		
		// Da spostare nella vista quando si fara' la separazione View-Controller
		this.pnlRoutingNavigation.changeStartAddress();
		
		this.pnlRoutingNavigation.submit();
		
		if (typeof street == "undefined") {
    		this.model.geometry = geometry;
    		this.model.srsName = srsName;
        	this.pnlReverseGeocoding.reverseGeocode("RGRid:STARTPOINT", geometry, srsName);
    	}
    },
    setEndAddress: function(geometry, srsName, street) {
    	this.model.endPoint = new ToloOLSVertex(
    		street || ToloI18n.getMsg("ToloOLSPanelExt.setEndAddress.arrivo"),
    		geometry.clone()
    	);
    	
    	if (this.paramsJS.mappe.SRID != srsName) {
	    	this.model.endPoint.point.transform(srsName, this.paramsJS.mappe.SRID);
    	}
    	
		// Da spostare nella vista quando si fara' la separazione View-Controller
		this.pnlRoutingNavigation.changeEndAddress();
		
		this.pnlRoutingNavigation.submit();
		
		if (typeof street == "undefined") {
    		this.model.geometry = geometry;
    		this.model.srsName = srsName;
        	this.pnlReverseGeocoding.reverseGeocode("RGRid:ENDPOINT", geometry, srsName);
    	}
    },
    addViaAddress: function(geometry, srsName, street) {
//        this._addViaAddress(geometry, srsName, street);
    	var viaId = this.model.viaPointId++;
    	
        var viaPoint = new ToloOLSVertex(
    		street || ToloI18n.getMsg("ToloOLSPanelExt.addViaAddress.intermedio"),
    		geometry.clone(),
    		viaId
	    );
        
    	if (this.paramsJS.mappe.SRID != srsName) {
    		viaPoint.point.transform(srsName, this.paramsJS.mappe.SRID);
    	}
        
        this.model.viaPoints.push(viaPoint);

		// Da spostare nella vista quando si fara' la separazione View-Controller
    	this.pnlRoutingNavigation.changeViaAddresses();
        this.pnlViaList.changeViaAddresses();
		
		this.pnlRoutingNavigation.submit();
		
		if (typeof street == "undefined") {
    		this.model.geometry = geometry;
    		this.model.srsName = srsName;
        	this.pnlReverseGeocoding.reverseGeocode("RGRid:VIAPOINT:" + viaId, geometry, srsName);
    	}
		
		return viaId;
    },
    setMethod: function(method) {
    	this.model.method = method;
    	
		// Da spostare nella vista quando si fara' la separazione View-Controller
    	this.pnlRoutingNavigation.changeMethod();
    	
		this.pnlRoutingNavigation.submit();
    },
    moveViaAddress: function(viaId, geometry, srsName) {
		for (var i = 0; i < this.model.viaPoints.length; i++) {
			if (this.model.viaPoints[i].id == viaId) {
				this.model.viaPoints[i].point = geometry.clone();
				
		    	if (this.paramsJS.mappe.SRID != srsName) {
		    		this.model.viaPoints[i].point.transform(srsName, this.paramsJS.mappe.SRID);
		    	}
		    	
				this.pnlRoutingNavigation.submit();
		    	
	    		this.model.geometry = geometry;
	    		this.model.srsName = srsName;
	        	this.pnlReverseGeocoding.reverseGeocode("RGRid:VIAPOINT:" + viaId, geometry, srsName);
				break;
			}
		}
    },
    reset: function() {
		this.model.startPoint = null;
		this.model.endPoint = null;
    	this.model.viaPoints = [];
    	this.model.viaPointId = 0;
    	this.model.method = 'Fastest';
    	this.model.routeResponse = null;
    	
		this.pnlRoutingNavigation.changeStartAddress();
		this.pnlRoutingNavigation.changeEndAddress();
    	this.pnlRoutingNavigation.changeViaAddresses();
        this.pnlViaList.changeViaAddresses();
    	this.pnlRoutingNavigation.changeMethod();
    	this.wndNavigationList.close();
    },
    
    routingInformationSelect: function(instructionId) {
    	this.pnlNavigationList.routingInformationSelect(instructionId);
	}, 
	
	routingInformationDeSelect: function(instructionId) {
		this.pnlNavigationList.routingInformationDeSelect(instructionId);
	}
    
});
/*!
 * CTemplate
 * Version 1.1
 * Copyright(c) 2011-2013 Skirtle's Den
 * License: http://skirtlesden.com/ux/ctemplate
 */
Ext.define('Skirtle.CTemplate', {
    extend: 'Ext.XTemplate',

    statics: {
        AUTO_ID: 0
    },

    // May need to be increased if components are included deeper in the data object
    copyDepth: 10,

    // Placeholder element template. Should be changed in tandem with getPlaceholderEl()
    cTpl: '<p id="ctemplate-{0}-{1}"></p>',

    // Flag
    isCTemplate: true,

    constructor: function() {
        var me = this;

        me.callParent(arguments);

        me.id = ++me.statics().AUTO_ID;

        me.reset();
    },

    /* Takes a recursive copy of the values provided, switching out components for placeholder values. The component ids
     * are recorded and injectComponents() uses the ids to find the placeholder elements in the DOM and switch in the
     * components.
     */
    copyValues: function(values, depth) {
        var me = this,
            id,
            copy = {},
            copyDepth = depth || me.copyDepth;

        if (copyDepth === 1) {
            return values;
        }

        if (Ext.isArray(values)) {
            return Ext.Array.map(values, function(value) {
                return me.copyValues(value, copyDepth - 1);
            });
        }

        if (!Ext.isObject(values)) {
            return values;
        }

        // This is the key sleight-of-hand that makes the whole thing work
        if (values.isComponent) {
            id = values.getId();
            me.ids.push(id);
            return Ext.String.format(me.cTpl, id, me.id);
        }

        Ext.Object.each(values, function(key, value) {
            // $comp is a special value for a renderTpl that references the current component
            copy[key] = key === '$comp' ? value : me.copyValues(value, copyDepth - 1);
        });

        return copy;
    },

    // Override
    doInsert: function() {
        var ret = this.callParent(arguments);

        // There's no guarantee this will succeed so we still need polling as well
        this.injectComponents();

        return ret;
    },

    /* We have to resort to polling for component injection as we don't have full control over when the generated HTML
     * will be added to the DOM
     */
    doPolling: function(interval) {
        var me = this;

        me.pollInterval = interval;

        if (me.pollId) {
            clearTimeout(me.pollId);
        }

        me.pollId = Ext.defer(me.injectComponents, interval, me);
    },

    getPlaceholderEl: function(id) {
        return Ext.get('ctemplate-' + id + '-' + this.id);
    },

    /* Attempts to substitute all placeholder elements with the real components. If a component is successfully injected
     * or it has been destroyed then it won't be attempted again. This method is repeatedly invoked by a polling
     * mechanism until no components remain, however relying on the polling is not advised. Instead it is preferable to
     * call this method directly as soon as the generated HTML is inserted into the DOM.
     */
    injectComponents: function() {
        var me = this,
            ids = me.ids,
            index = ids.length - 1,
            id,
            cmp,
            placeholderEl;

        // Iterate backwards because we remove some elements in the loop
        for ( ; index >= 0 ; --index) {
            id = ids[index];
            cmp = Ext.getCmp(id);
            placeholderEl = me.getPlaceholderEl(id);

            if (me.renderComponent(cmp, placeholderEl) || !cmp) {
                // Either we've successfully done the switch or the component has been destroyed
                Ext.Array.splice(ids, index, 1);

                if (placeholderEl) {
                    placeholderEl.remove();
                }
            }
        }

        if (ids.length) {
            // Some components have not been injected. Polling acts both to do deferred injection and as a form of GC
            me.doPolling(me.pollInterval * 1.5);
        }
    },

    // Override
    overwrite: function(el) {
        var dom,
            firstChild,
            ret;

        /* In IE setting the innerHTML will destroy the nodes for the previous content. If we try to reuse components it
         * will fail as their DOM nodes will have been torn apart. We can't defend against external updates to the DOM
         * but we can guard against the case where all updates come through this template.
         */
        if (Ext.isIE) {
            dom = Ext.getDom(el);

            while (firstChild = dom.firstChild) {
                dom.removeChild(firstChild);
            }
        }

        ret = this.callParent(arguments);

        // There's no guarantee this will succeed so we still need polling as well
        this.injectComponents();

        return ret;
    },

    renderComponent: function(cmp, placeholderEl) {
        if (cmp && placeholderEl) {
            var parent = placeholderEl.parent();

            if (cmp.rendered) {
                // Move a component that has been rendered previously
                cmp.getEl().replace(placeholderEl);
            }
            else {
                cmp.render(parent, placeholderEl);
            }

            if (Ext.isIE6) {
                // Some components (mostly form fields) reserve space but fail to show up without a repaint in IE6
                parent.repaint();
            }

            return true;
        }

        return false;
    },

    reset: function() {
        var me = this;

        // The ids of injected components that haven't yet been rendered
        me.ids = [];

        if (me.pollId) {
            clearTimeout(me.pollId);
            me.pollId = null;
        }
    }
}, function(ctemplate) {
    var apply = function() {
        var me = this,
            args = Ext.Array.slice(arguments);

        args[0] = me.copyValues(args[0]);

        // As we're returning an HTML string/array we can't actually complete the injection here
        me.doPolling(10);

        return me.callParent(args);
    };

    // The main override is different depending on whether we're using ExtJS 4.0 or 4.1+
    if (ctemplate.prototype.applyOut) {
        // 4.1+
        ctemplate.override({
            applyOut: apply
        });
    }
    else {
        // 4.0
        ctemplate.override({
            applyTemplate: apply
        });

        ctemplate.createAlias('apply', 'applyTemplate');
    }
});/*!
 * Component Column
 * Version 1.1
 * Copyright(c) 2011-2013 Skirtle's Den
 * License: http://skirtlesden.com/ux/component-column
 */
Ext.define('Skirtle.grid.column.Component', {
    alias: 'widget.componentcolumn',
    extend: 'Ext.grid.column.Column',
    requires: ['Skirtle.CTemplate'],

    // Whether or not to automatically resize the components when the column resizes
    autoWidthComponents: true,

    // Whether or not to destroy components when they are removed from the DOM
    componentGC: true,

    // Override the superclass - this must always be true or odd things happen, especially in IE
    hasCustomRenderer: true,

    // The estimated size of the cell frame. This is updated once there is a cell where it can be measured
    lastFrameWidth: 12,

    /* Defer durations for updating the component width when a column resizes. Required when a component has an animated
     * resize that causes the scrollbar to appear/disappear. Otherwise the animated component can end up the wrong size.
     *
     * For ExtJS 4.0 both delays are required. For 4.1 just having the 10ms delay seems to be sufficient.
     */
    widthUpdateDelay: [10, 400],

    constructor: function(cfg) {
        var me = this;

        me.callParent(arguments);

        // Array of component ids for both component queries and GC
        me.compIds = [];

        // We need a dataIndex, even if it doesn't correspond to a real field
        me.dataIndex = me.dataIndex || Ext.id(null, 'cc-dataIndex-');

        me.tpl = me.createTemplate(me.tpl);
        me.renderer = me.createRenderer(me.renderer);

        me.registerColumnListeners();
    },

    addRefOwner: function(child) {
        var me = this,
            fn = me.refOwnerFn || (me.refOwnerFn = function() {
                return me;
            });

        if (me.extVersion < 40200) {
            // Component queries for ancestors use getBubbleTarget in 4.1 ...
            child.getBubbleTarget = fn;
        }
        else {
            // ... and getRefOwner in 4.2+
            child.getRefOwner = fn;
        }
    },

    applyTemplate: function(data, value) {
        if (Ext.isDefined(value)) {
            data[this.dataIndex] = value;
        }

        return this.tpl.apply(data);
    },

    /* In IE setting the innerHTML will destroy the nodes for the previous content. If we try to reuse components it
     * will fail as their DOM nodes will have been torn apart. To defend against this we must remove the components
     * from the DOM just before the grid view is refreshed.
     */
    beforeViewRefresh: function() {
        if (Ext.isIE) {
            var ids = this.compIds,
                index = 0,
                len = ids.length,
                item,
                el,
                parentEl;

            for ( ; index < len ; index++) {
                if ((item = Ext.getCmp(ids[index])) && (el = item.getEl()) && (el = el.dom) && (parentEl = el.parentNode)) {
                    parentEl.removeChild(el);
                }
            }
        }
    },

    calculateFrameWidth: function(component) {
        var el = component.getEl(),
            parentDiv = el && el.parent(),
            // By default the TD has no padding but it is quite common to add some via a tdCls
            parentTd = parentDiv && parentDiv.parent();

        if (parentTd) {
            // Cache the frame width so that it can be used as a 'best guess' in cases where we don't have the elements
            return this.lastFrameWidth = parentDiv.getFrameWidth('lr') + parentTd.getFrameWidth('lr');
        }
    },

    createRenderer: function(renderer) {
        var me = this;

        return function(value, p, record) {
            var data = Ext.apply({}, record.data, record.getAssociatedData());

            if (renderer) {
                // Scope must be this, not me
                value = renderer.apply(this, arguments);
            }

            // Process the value even with no renderer defined as the record may contain a component config
            value = me.processValue(value);

            return me.applyTemplate(data, value);
        };
    },

    createTemplate: function(tpl) {
        return tpl && tpl.isTemplate
            ? tpl
            : Ext.create('Skirtle.CTemplate', tpl || ['{', this.dataIndex ,'}']);
    },

    destroyChild: function(child) {
        child.destroy();
    },

    getRefItems: function(deep) {
        var items = this.callParent([deep]),
            ids = this.compIds,
            index = 0,
            len = ids.length,
            item;

        for ( ; index < len ; index++) {
            if (item = Ext.getCmp(ids[index])) {
                items.push(item);

                if (deep && item.getRefItems) {
                    items.push.apply(items, item.getRefItems(true));
                }
            }
        }

        return items;
    },

    onChildAfterRender: function(child) {
        this.resizeChild(child);
    },

    onChildBoxReady: function(child) {
        // Pass false to avoid triggering deferred resize, the afterrender listener will already cover those cases
        this.resizeChild(child, false);
    },

    onChildDestroy: function(child) {
        Ext.Array.remove(this.compIds, child.getId());
    },

    onChildResize: function() {
        this.redoScrollbars();
    },

    onColumnResize: function(column) {
        column.resizeAll();
    },

    onColumnShow: function(column) {
        column.resizeAll();
    },

    // This is called in IE 6/7 as the components can still be seen even when a column is hidden
    onColumnVisibilityChange: function(column) {
        var items = column.getRefItems(),
            index = 0,
            length = items.length,
            visible = !column.isHidden();

        // In practice this probably won't help but it shouldn't hurt either
        Ext.suspendLayouts && Ext.suspendLayouts();

        for ( ; index < length ; ++index) {
            items[index].setVisible(visible);
        }

        Ext.resumeLayouts && Ext.resumeLayouts(true);
    },

    onDestroy: function() {
        Ext.destroy(this.getRefItems());

        this.callParent();
    },

    // Override
    onRender: function() {
        this.registerViewListeners();
        this.callParent(arguments);
    },

    // View has changed, may be a full refresh or just a single row
    onViewChange: function() {
        var me = this,
            tpl = me.tpl;

        // Batch the resizing of child components until after they've all been injected
        me.suspendResizing();

        if (tpl.isCTemplate) {
            // No need to wait for the polling, the sooner we inject the less painful it is
            tpl.injectComponents();

            // If the template picked up other components in the data we can just ignore them, they're not for us
            tpl.reset();
        }

        // A view change could mean scrollbar problems. Note this won't actually do anything till we call resumeResizing
        me.redoScrollbars();

        me.resumeResizing();
        
        me.performGC();
    },

    // Component GC, try to stop components leaking
    performGC: function() {
        var compIds = this.compIds,
            index = compIds.length - 1,
            comp,
            el;

        for ( ; index >= 0 ; --index) {
            // Could just assume that the component id is the el id but that seems risky
            comp = Ext.getCmp(compIds[index]);
            el = comp && comp.getEl();

            if (!el || (this.componentGC && (!el.dom || Ext.getDom(Ext.id(el)) !== el.dom))) {
                // The component is no longer in the DOM
                if (comp && !comp.isDestroyed) {
                    comp.destroy();
                }
            }
        }
    },

    processValue: function(value) {
        var me = this,
            compIds = me.compIds,
            id, initialWidth, dom, parent;

        if (Ext.isObject(value) && !value.isComponent && value.xtype) {
            // Do not default to a panel, not only would it be an odd default but it makes future enhancements trickier
            value = Ext.widget(value.xtype, value);
        }

        if (value && value.isComponent) {
            id = value.getId();

            // When the view is refreshed the renderer could return a component that's already in the list
            if (!Ext.Array.contains(compIds, id)) {
                compIds.push(id);
            }

            me.addRefOwner(value);
            me.registerListeners(value);

            if (value.rendered) {
                /* This is only necessary in IE because it is just another manifestation of the innerHTML problems.
                 * The problem occurs when a record value is changed and the components in that same row are being
                 * reused. The view doesn't go through a full refresh, instead it performs a quick update on just the
                 * one row. Unfortunately this nukes the existing components so we need to remove them first.
                 */
                if (Ext.isIE) {
                    // TODO: Should this be promoted to CTemplate?
                    dom = value.el.dom;
                    parent = dom.parentNode;

                    if (parent) {
                        if (me.extVersion === 40101) {
                            // Workaround for the bugs in Element.syncContent - p tag matches CTemplate.cTpl
                            Ext.core.DomHelper.insertBefore(dom, {tag: 'p'});
                        }

                        // TODO: Removing the element like this could fall foul of Element GC
                        parent.removeChild(dom);
                    }
                }
            }
            else if (me.autoWidthComponents) {
                /* Set the width to a 'best guess' before the component is rendered to ensure that the component's
                 * layout is using a configured width and not natural width. This avoids problems with 4.1.1 where
                 * subsequent calls to setWidth are ignored because it believes the width is already correct but only
                 * the outermost element is actually sized correctly. We could use an arbitrary width but instead we
                 * make a reasonable guess at what the actual width will be to try to avoid extra resizing.
                 */
                initialWidth = me.getWidth() - me.lastFrameWidth;

                // Impose a minimum width of 4, we really don't want negatives values or NaN slipping through
                initialWidth = initialWidth > 4 ? initialWidth : 4;

                value.setWidth(initialWidth);
            }

            // Part of the same IE 6/7 hack as onColumnVisibilityChange
            if ((Ext.isIE6 || Ext.isIE7) && me.isHidden()) {
                value.hide();
            }
        }

        return value;
    },

    redoScrollbars: function() {
        var me = this,
            grid = me.up('tablepanel');

        if (grid) {
            // The presence of a resizeQueue signifies that we are currently suspended
            if (me.resizeQueue) {
                me.redoScrollbarsRequired = true;
                return;
            }

            // After components are injected the need for a grid scrollbar may need redetermining
            if (me.extVersion < 40100) {
                // 4.0
                grid.invalidateScroller();
                grid.determineScrollbars();
            }
            else {
                // 4.1+
                grid.doLayout();
            }
        }
    },

    registerColumnListeners: function() {
        var me = this;

        if (me.autoWidthComponents) {
            // Need to resize children when the column resizes
            me.on('resize', me.onColumnResize);

            // Need to resize children when the column is shown as they can't be resized correctly while it is hidden
            me.on('show', me.onColumnShow);
        }

        if (Ext.isIE6 || Ext.isIE7) {
            me.on({
                hide: me.onColumnVisibilityChange,
                show: me.onColumnVisibilityChange
            });
        }
    },

    registerListeners: function(component) {
        var me = this;

        // Remove the component from the child list when it is destroyed
        component.on('destroy', me.onChildDestroy, me);

        if (me.autoWidthComponents) {
            // Need to resize children after render as some components (e.g. comboboxes) get it wrong otherwise
            component.on('afterrender', me.onChildAfterRender, me, {single: true});

            // With 4.1 boxready gives more reliable results than afterrender as it occurs after the initial sizing
            if (!me.extVersion < 40100) {
                component.on('boxready', me.onChildBoxReady, me, {single: true});
            }
        }

        // Need to redo scrollbars when a child resizes
        component.on('resize', me.onChildResize, me);
    },

    registerViewListeners: function() {
        var me = this,
            view = me.up('tablepanel').getView();

        me.mon(view, 'beforerefresh', me.beforeViewRefresh, me);
        me.mon(view, 'refresh', me.onViewChange, me);
        me.mon(view, 'itemupdate', me.onViewChange, me);
        me.mon(view, 'itemadd', me.onViewChange, me);
        me.mon(view, 'itemremove', me.onViewChange, me);
    },

    resizeAll: function() {
        var me = this;

        me.suspendResizing();
        me.resizeQueue = me.getRefItems();
        me.resumeResizing();
    },

    resizeChild: function(component, defer) {
        var me = this,
            frameWidth,
            newWidth,
            oldWidth,
            resizeQueue;

        if (me.resizingSuspended) {
            resizeQueue = me.resizeQueue;

            if (!Ext.Array.contains(resizeQueue, component)) {
                resizeQueue.push(component);
            }

            return;
        }

        frameWidth = me.calculateFrameWidth(component);

        // TODO: Should we destroy the component here if it doesn't have a parent element? Already picked up anyway?
        if (Ext.isNumber(frameWidth)) {
            newWidth = me.getWidth() - frameWidth;
            oldWidth = component.getWidth();

            // Returns true if a resize actually happened
            if (me.setChildWidth(component, newWidth, oldWidth)) {
                // Avoid an infinite resizing loop, deferring will only happen once
                if (defer !== false) {
                    // Do the sizing again after a delay. This is because child panel collapse animations undo our sizing
                    Ext.each(me.widthUpdateDelay, function(delay) {
                        Ext.defer(me.resizeChild, delay, me, [component, false]);
                    });
                }
            }
        }
    },

    resumeResizing: function() {
        var me = this,
            index = 0,
            resizeQueue = me.resizeQueue,
            len = resizeQueue.length;

        if (!--me.resizingSuspended) {
            for ( ; index < len ; ++index) {
                me.resizeChild(resizeQueue[index]);
            }

            me.resizeQueue = null;

            if (me.redoScrollbarsRequired) {
                me.redoScrollbars();
            }
        }
    },

    setChildWidth: function(component, newWidth, oldWidth) {
        if (oldWidth === newWidth) {
            return false;
        }

        component.setWidth(newWidth);

        return true;
    },

    suspendResizing: function() {
        var me = this;

        me.resizingSuspended = (me.resizingSuspended || 0) + 1;

        if (!me.resizeQueue) {
            me.resizeQueue = [];
        }
    }
}, function(cls) {
    var proto = cls.prototype,
        version = Ext.getVersion();

    // ExtJS version detection
    proto.extVersion = (version.getMajor() * 100 + version.getMinor()) * 100 + version.getPatch();

    // 4.1.1 initially reported its version as 4.1.0
    if (Ext.Element.prototype.syncContent && version.toString() === '4.1.0') {
        proto.extVersion = 40101;
    }
});Ext.namespace("TolomeoExt.Styler.Renderer");

Ext.define("TolomeoExt.Styler.Renderer.DefaultSymbolizer", {
	singleton: true,
	fillColor: "#000000",
	fillOpacity: 1,
	fontColor: "#000000",
	fontSize: 10,
	haloColor: "#FFFFFF",
	haloOpacity: 1,
	haloRadius: 1,
	pointRotation: 0,
	strokeColor: "#000000",
	strokeDashstyle: "solid",
	strokeOpacity: 1,
	strokeWidth: 2
});
Ext.namespace("TolomeoExt.Styler.slider");

Ext.define("TolomeoExt.Styler.slider.Tip", {
	extend: "Ext.slider.Tip",
	hover: true,
	dragging: false,
	init: function(slider) {
		if (this.hover) {
			slider.on("render", this.registerThumbListeners, this);
		}
		this.slider = slider;
		TolomeoExt.Styler.slider.Tip.superclass.init.apply(this, arguments);
	},
	registerThumbListeners: function() {
		for (var i = 0, len = this.slider.thumbs.length; i < len; ++i) {
			this.slider.thumbs[i].el.on({
				"mouseover": this.createHoverListener(i),
				"mouseout": function() {
					if (!this.dragging) {
						this.hide.apply(this, arguments);
					}
				},
				scope: this
			});
		}
	},
	createHoverListener: function(index) {
		return Ext.Function.pass(function() {
			this.onSlide(this.slider, {}, this.slider.thumbs[index]);
			this.dragging = false;
		}, [], this);
	},
	onSlide: function(slider, e, thumb) {
		this.dragging = true;
		TolomeoExt.Styler.slider.Tip.superclass.onSlide.apply(this, arguments);
	}
});
Ext.namespace("TolomeoExt.Styler.form");

Ext.define("TolomeoExt.Styler.form.ColorField", {
	extend: "Ext.form.TextField",
	alias: "widget.styler_colorfield",
	cssColors: {
		aqua: "#00FFFF",
		black: "#000000",
		blue: "#0000FF",
		fuchsia: "#FF00FF",
		gray: "#808080",
		green: "#008000",
		lime: "#00FF00",
		maroon: "#800000",
		navy: "#000080",
		olive: "#808000",
		purple: "#800080",
		red: "#FF0000",
		silver: "#C0C0C0",
		teal: "#008080",
		white: "#FFFFFF",
		yellow: "#FFFF00"
	},
	defaultBackground: "#ffffff",
	colorPicker: null,
	colorPickerDialog: null,
	enableKeyEvents: true,
	initComponent: function() {
		this.value = this.value.trim();
		this.colorPicker = Ext.create("Ext.picker.Color", {
			listeners: {
				select: function(picker, selColor) {
					this.setValue("#" + selColor);
					this.colorField();
				},
				scope: this
			}
		});
		this.colorPickerDialog = Ext.create("Ext.Window", {
			title: "Cattura Colore",
			closeAction: "hide",
			items: [
				this.colorPicker
			]
		});
		if (this.value) {
			this.value = this.hexToColor(this.value);
		}
		TolomeoExt.Styler.form.ColorField.superclass.initComponent.call(this);
		this.on({
			render: this.colorField,
			change: this.colorField,
			focus: this.fieldFocus,
			scope: this
		});
	},
	isDark: function(hex) {
		var dark = false;
		if (hex) {
			var r = parseInt(hex.substring(1, 3), 16) / 255;
			var g = parseInt(hex.substring(3, 5), 16) / 255;
			var b = parseInt(hex.substring(5, 7), 16) / 255;
			var brightness = (r * 0.299) + (g * 0.587) + (b * 0.144);
			dark = brightness < 0.5;
		}
		return dark;
	},
	colorField: function() {
		var color = this.colorToHex(this.getValue()) || this.defaultBackground;
		this.inputEl.setStyle({
			"background": color,
			"color": this.isDark(color) ? "#ffffff" : "#000000"
		});
	},
	getHexValue: function() {
		return this.colorToHex(TolomeoExt.Styler.form.ColorField.superclass.getValue.apply(this, arguments));
	},
	getValue: function() {
		var v = this.getHexValue();
		var o = this.initialConfig.value;
		if (v === this.hexToColor(o)) {
			v = o;
		}
		return v;
	},
	setValue: function(value) {
		TolomeoExt.Styler.form.ColorField.superclass.setValue.apply(this, [this.hexToColor(value)]);
	},
	colorToHex: function(color) {
		if (!color) {
			return color;
		}
		var hex;
		if (color.match(/^#[0-9a-f]{6}$/i)) {
			hex = color;
		} else {
			hex = this.cssColors[color.toLowerCase()] || null;
		}
		return hex;
	},
	hexToColor: function(hex) {
		if (!hex) {
			return hex;
		}
		var color = hex;
		for (var c in this.cssColors) {
			if (this.cssColors[c] == color.toUpperCase()) {
				color = c;
				break;
			}
		}
		return color;
	},
	fieldFocus: function(field) {
		if (this.colorPicker.colors.indexOf(this.getValue().substring(1)) == -1) {
			this.colorPicker.colors.push(this.getValue().substring(1));
		}
		this.colorPicker.select(this.getValue(), true);
		var color = this.colorToHex(this.getValue()) || this.defaultBackground;
		this.colorPickerDialog.show();
	}
});
Ext.namespace("TolomeoExt.Styler.form");

Ext.define("TolomeoExt.Styler.form.FontComboBox", {
	extend: "Ext.form.ComboBox",
	alias: "widget.styler_fontcombo",
	fonts: ["Serif", "SansSerif", "Arial", "Courier New", "Tahoma", "Times New Roman", "Verdana"],
	defaultFont: "Serif",
	allowBlank: false,
	mode: "local",
	triggerAction: "all",
	editable: false,
	initComponent: function() {
		var fonts = this.fonts || TolomeoExt.Styler.form.FontComboBox.prototype.fonts;
		var defaultFont = this.defaultFont;
		if (fonts.indexOf(this.defaultFont) === -1) {
			defaultFont = fonts[0];
		}
		var defConfig = {
			displayField: "field1",
			valueField: "field1",
			store: fonts,
			value: defaultFont,
			tpl: new Ext.XTemplate('<tpl for=".">' + '<div class="x-combo-list-item">' + '<span style="font-family: {field1};">{field1}</span>' + '</div></tpl>')
		};
		Ext.applyIf(this, defConfig);
		TolomeoExt.Styler.form.FontComboBox.superclass.initComponent.call(this);
	}
});
Ext.namespace("TolomeoExt.Styler.form");

Ext.define("TolomeoExt.Styler.form.ComparisonComboBox", {
	extend: "Ext.form.ComboBox",
	alias: "widget.styler_comparisoncombo",
	allowedTypes: [
		{value: OpenLayers.Filter.Comparison.EQUAL_TO, name: "="},
		{value: OpenLayers.Filter.Comparison.NOT_EQUAL_TO, name: "<>"},
		{value: OpenLayers.Filter.Comparison.LESS_THAN, name: "<"},
		{value: OpenLayers.Filter.Comparison.GREATER_THAN, name: ">"},
		{value: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, name: "<="},
		{value: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, name: ">="},
		{value: OpenLayers.Filter.Comparison.LIKE, name: "like"}
	],
	allowBlank: false,
	queryMode: "local",
	triggerAction: "all",
	width: 50,
	editable: false,
	initComponent: function() {
		var defConfig = {
			displayField: "name",
			valueField: "value",
			store: Ext.create("Ext.data.JsonStore", {
				data: this.allowedTypes,
				fields: ["value", "name"]
			}),
			value: (this.value === undefined) ? this.allowedTypes[0]["value"] : this.value
		};
		Ext.apply(this, defConfig);
		TolomeoExt.Styler.form.ComparisonComboBox.superclass.initComponent.call(this);
	}
});
Ext.namespace("TolomeoExt.Styler.form");

Ext.define("TolomeoExt.Styler.form.FilterField", {
	extend: "Ext.form.FieldContainer",
	alias: "widget.styler_filterfield",
	filter: null,
	attributes: null,
	attributesComboConfig: null,
	initComponent: function() {
		if (!this.filter) {
			this.filter = this.createDefaultFilter();
		}
		if (!this.attributes) {
			this.attributes = new GeoExt.data.AttributeStore();
		}
		var defAttributesComboConfig = {
			xtype: "combo",
			store: this.attributes,
			editable: false,
			triggerAction: "all",
			allowBlank: false,
			displayField: "name",
			valueField: "name",
			value: this.filter.property,
			queryMode: "local",
			listeners: {
				select: function(combo, record) {
					this.filter.property = record[0].get("name");
					this.fireEvent("change", this.filter);
				},
				scope: this
			},
			width: 120
		};
		this.attributesComboConfig = this.attributesComboConfig || {};
		Ext.applyIf(this.attributesComboConfig, defAttributesComboConfig);
		this.items = this.createFilterItems();
		this.addEvents("change");
		TolomeoExt.Styler.form.FilterField.superclass.initComponent.call(this);
	},
	createDefaultFilter: function() {
		return new OpenLayers.Filter.Comparison();
	},
	createFilterItems: function() {
		return [this.attributesComboConfig, {
			xtype: "styler_comparisoncombo",
			value: this.filter.type,
			listeners: {
				select: function(combo, record) {
					this.filter.type = record[0].get("value");
					this.fireEvent("change", this.filter);
				},
				scope: this
			}
		}, {
			xtype: "textfield",
			value: this.filter.value,
			width: 50,
			grow: true,
			growMin: 50,
			anchor: "100%",
			allowBlank: false,
			listeners: {
				change: function(el, value) {
					this.filter.value = value;
					this.fireEvent("change", this.filter);
				},
				scope: this
			}
		}];
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.FeatureRenderer", {
	extend: Ext.form.FieldContainer,
	//extend: Ext.container.Container,
	alias: "widget.styler_featurerenderer",
	feature: void 0,
	symbolizers: [OpenLayers.Feature.Vector.style["default"]],
	symbolType: "Polygon",
	resolution: 1,
	minWidth: 20,
	minHeight: 20,
	renderers: ["SVG", "VML", "Canvas"],
	rendererOptions: null,
	pointFeature: undefined,
	lineFeature: undefined,
	polygonFeature: undefined,
	textFeature: undefined,
	renderer: null,
	initComponent: function() {
		this.autoEl = {
			tag: "div",
			"class": this.imgCls ? this.imgCls : "",
			id: this.getId()
		};
		this.callParent(arguments);
		Ext.applyIf(this, {
			pointFeature: new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0, 0)),
			lineFeature: new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([new OpenLayers.Geometry.Point(-8, -3), new OpenLayers.Geometry.Point(-3, 3), new OpenLayers.Geometry.Point(3, -3), new OpenLayers.Geometry.Point(8, 3)])),
			polygonFeature: new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(-8, -4), new OpenLayers.Geometry.Point(-6, -6), new OpenLayers.Geometry.Point(6, -6), new OpenLayers.Geometry.Point(8, -4), new OpenLayers.Geometry.Point(8, 4), new OpenLayers.Geometry.Point(6, 6), new OpenLayers.Geometry.Point(-6, 6), new OpenLayers.Geometry.Point(-8, 4)])])),
			textFeature: new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0, 0))
		});
		this.feature || this.setFeature(null, {
			draw: false
		});
		this.addEvents("click")
	},
	initCustomEvents: function() {
		this.clearCustomEvents();
		this.el.on("click", this.onClick, this)
	},
	clearCustomEvents: function() {
		this.el && this.el.removeAllListeners && this.el.removeAllListeners()
	},
	onClick: function() {
		this.fireEvent("click", this)
	},
	onRender: function(a, b) {
		this.el || (this.el = document.createElement("div"), this.el.id = this.getId());
		(!this.renderer || !this.renderer.supported()) && this.assignRenderer();
		this.renderer.map = {
			getResolution: Ext.Function.bind(function() {
				return this.resolution
			}, this)
		};
		this.callParent(arguments);
		this.drawFeature()
	},
	afterRender: function() {
		this.callParent(arguments);
		this.initCustomEvents()
	},
	onResize: function(a, b) {
		this.setRendererDimensions();
		this.callParent(arguments)
	},
	setRendererDimensions: function() {
		var a = this.feature.geometry.getBounds(),
			b = a.getWidth(),
			c = a.getHeight(),
			d = this.initialConfig.resolution;
		d || (d = Math.max(b / this.width || 0, c / this.height || 0) || 1);
		this.resolution = d;
		var b = Math.max(this.width || this.minWidth, b / d),
			c = Math.max(this.height || this.minHeight, c / d),
			a = a.getCenterPixel(),
			e = b * d / 2,
			d = c * d / 2,
			d = new OpenLayers.Bounds(a.x - e, a.y - d, a.x + e, a.y + d);
		this.renderer.setSize(new OpenLayers.Size(Math.round(b), Math.round(c)));
		this.renderer.setExtent(d, !0)
	},
	assignRenderer: function() {
		for (var a =
				0, b = this.renderers.length; a < b; ++a) {
			var c = OpenLayers.Renderer[this.renderers[a]];
			if (c && c.prototype.supported()) {
				this.renderer = new c(this.el, this.rendererOptions);
				break
			}
		}
	},
	setSymbolizers: function(a, b) {
		this.symbolizers = a;
		(!b || b.draw) && this.drawFeature()
	},
	setSymbolType: function(a, b) {
		this.symbolType = a;
		this.setFeature(null, b)
	},
	setFeature: function(a, b) {
		this.feature = a || this[this.symbolType.toLowerCase() + "Feature"];
		(!b || b.draw) && this.drawFeature()
	},
	drawFeature: function() {
		this.renderer.clear();
		this.setRendererDimensions();
		for (var a, b, c = 0, d = this.symbolizers.length; c < d; ++c) a = this.symbolizers[c], b = this.feature, a instanceof OpenLayers.Symbolizer ? (a = a.clone(), OpenLayers.Symbolizer.Text && (a instanceof OpenLayers.Symbolizer.Text && !1 === a.graphic) && (a.fill = a.stroke = !1), this.initialConfig.feature || (b = a.CLASS_NAME.split(".").pop().toLowerCase(), b = this[b + "Feature"])) : a = Ext.apply({}, a), this.renderer.drawFeature(b.clone(), a)
	},
	update: function(a) {
		a = a || {};
		a.feature ? this.setFeature(a.feature, {
			draw: !1
		}) : a.symbolType && this.setSymbolType(a.symbolType, {
			draw: !1
		});
		a.symbolizers && this.setSymbolizers(a.symbolizers, {
			draw: !1
		});
		this.drawFeature()
	},
	beforeDestroy: function() {
		this.clearCustomEvents();
		this.renderer && this.renderer.destroy()
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("Field", {
	extend: "Ext.data.Model",
	fields: [{
		name: "name",
		type: "string"
	}]
});

Ext.define("TolomeoExt.Styler.StylePanel", {
	extend: "Ext.Panel",
	alias: "widget.styler_stylepanel",
	statics:{
		styleToSld: function(style) {

		    	var sld = {
						namedLayers: {
							"Default Styler": {
								userStyles: [
									style
								],
								name: "Default Styler"
							}
						},
						version: "1.0.0"
					}
					
				var format = new OpenLayers.Format.SLD({
					multipleSymbolizers: true
				});
		    	
		    	return format.write(sld);
		    },
		    
	    sldToStyle: function(sld) {
	    		
			var format = new OpenLayers.Format.SLD({
				multipleSymbolizers: true
			});
			
			var style = format.read(sld).namedLayers["Default Styler"].userStyles[0];
	    	
	    	return style; 
	    }
	},
		
	tipoGenerazioneStile: 0,
	
	
	layout: 'border',
  	actualStyle: null,
  	styleRecord: null,
  	rulesPanel: null,
  	selectedRule: null,
  	selectedRuleIndex: null,
  	selectedRulePanel: null,
  	mapPanel: null,
  	
  	layerGeomType: null,
  	
  	
  	/** 
	 * Property: TOLOMEOServer
	 * {String}
	 */
	TOLOMEOServer: null,
	
	/** 
	 * Property: TOLOMEOStaticRoot
	 * {String}
	 */
	TOLOMEOStaticRoot: null,

	/** 
	 * Property: TOLOMEOContext
	 * {String}
	 */
	TOLOMEOContext: null,
  
	getSymbolTypeFromRule: function(rule) {
		var candidate, type;
		for (var i = 0, ii = rule.symbolizers.length; i < ii; ++i) {
			candidate = rule.symbolizers[i];
			if (!(candidate instanceof OpenLayers.Symbolizer.Text)) {
				type = candidate.CLASS_NAME.split(".").pop();
				break;
			}
		}
		return type;
	},
	
	initComponent: function() {

		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);
		var me = this;
		
		if (this.styleRecord==null) {
			this.styleRecord = Ext.create('modelloDatiStile', {});
		} else {
			this.actualStyle = TolomeoExt.Styler.StylePanel.sldToStyle(this.styleRecord.get('sldtext'));
		}
		
  		this.addEvents("stylecanceled", "stylesaved", "ruleselected", "ruleadded", "ruleremoved");
  		
  		this.nomeField = Ext.create('Ext.form.field.Text', {
  			fieldLabel: "Nome",
			value: (this.styleRecord) ? this.styleRecord.get('name') : "",
			width: 100
  		});
  		
  		this.titoloField = Ext.create('Ext.form.field.Text', {
  			fieldLabel: "Titolo",
			value: (this.styleRecord) ? this.styleRecord.get('title') : "",
			width: 100
  		});
  		/*
  		this.descrizioneField = Ext.create('Ext.form.field.Text', {
  			fieldLabel: "Descrizione",
			value: (this.styleRecord) ? this.styleRecord.get('styleAbstract') : "",
			width: 100
  		});*/ 
  		
  		var headPanel = Ext.create('Ext.Panel', {
  			region: 'north',
  			layout: 'form',
  			defaults: {
		  				style: {
							"padding": "0.3em 0 0 1em",
							"padding-left": "10px" 
						},
						labelWidth: 70
  					},
  			items: [this.nomeField, this.titoloField, this.descrizioneField]
  		});
  		
		var rulesStoreData = {
			items: []
		};
		if (this.actualStyle != null) {
			for (var ruleIndex = 0 ; ruleIndex < this.actualStyle.rules.length ; ruleIndex ++) {
				var rule = this.actualStyle.rules[ruleIndex];
				rulesStoreData.items[ruleIndex] = {
					name: rule.title,
					//symbol: 'Available',
						/*
						Ext.create("TolomeoExt.Styler.FeatureRenderer", {
						symbolType: this.getSymbolTypeFromRule(rule),
						symbolizers: rule.symbolizers
					})*/
					rule: rule
				};
			}
		}
		var rulesStore = Ext.create("Ext.data.Store", {
			storeId: "rulesStore",
			fields: ["name", "symbol", "rule"],
			data: rulesStoreData,
			autoSync: true,
			proxy: {
				type: "memory",
				reader: {
				  type: "json",
				  root: "items"
				}
			}
		});
		rulesStore.on('add', 
				function(store, records, index, eOpts ) {
					this.rulesPanel.getSelectionModel().select(index);
				}, this);
		
		this.rulesPanel = Ext.create("Ext.grid.Panel", {
			title: "Regole",
			region: 'west',
			split: true,
			store: Ext.data.StoreManager.lookup("rulesStore"),
			columns: [
				{
					text: "Nome",
					dataIndex: "name",
					width: 99
				}
				// Commentato in attesa di risolvere problema
				// FeatureRenderer estende Ext.form.FieldContainer che ha elemento bodyEl 
				// che viene valorizzato solo dopo il rendering, ma questo sembra andare in conflitto con 
				// l'uso in questo contesto
				/*,
				{
					text: "Simbolo",
					dataIndex: "rule",
					xtype: 'componentcolumn', 
		            renderer: function(rule, meta, record) {
		            	return  {
		            		xtype: 'styler_featurerenderer',
		            		symbolType: me.getSymbolTypeFromRule(rule),
							symbolizers: rule.symbolizers//,
							//width: 10,
							//height: 10
		            	};
		            },
					width: 50
				}*/
			],
			height: 200,
			width: 200,
			bbar: [{
					iconCls: "add",
					cls: 'clearCSS',
				    text: 'Aggiungi',
				    menu: {
				    	cls: 'clearCSS',
				    	items: [{
				    		text: 'Puntuale',
				    		menu: {
				    			cls: 'clearCSS',
				    			items: [{
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.SEMPLICE.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.SEMPLICE, 1);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.NATURAL_BREAK.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.NATURAL_BREAK, 1);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_COUNT.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_COUNT, 1);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_RANGE.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_RANGE, 1);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.VALORI_UNIVOCI.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.VALORI_UNIVOCI, 1);
				    				}
				    			}]
				    	
				    		}
				    	},{
				    		text: 'Lineare',
	        				menu: {
				    			cls: 'clearCSS',
				    			items: [{
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.SEMPLICE.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.SEMPLICE, 2);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.NATURAL_BREAK.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.NATURAL_BREAK, 2);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_COUNT.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_COUNT, 2);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_RANGE.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_RANGE, 2);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.VALORI_UNIVOCI.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.VALORI_UNIVOCI, 2);
				    				}
				    			}]
	        				}
		        		},{
		        			text: 'Poligonale',
		        			menu: {
				    			cls: 'clearCSS',
				    			items: [{
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.SEMPLICE.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.SEMPLICE, 3);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.NATURAL_BREAK.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.NATURAL_BREAK, 3);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_COUNT.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_COUNT, 3);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_RANGE.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.EQUAL_RANGE, 3);
				    				}
				    			}, {
				    				text: TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.VALORI_UNIVOCI.nome,
				    				scope: this,
				    				handler: function() {
				    					this.aggiungiRegolaHandler(TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.VALORI_UNIVOCI, 3);
				    				}
				    			}]
		        			}
		        		}]
					    
						} 
					},{
					text: "Rimuovi",
					iconCls: "delete",
					disabled: true,
					handler: function() {
						Ext.Msg.show({
							title: "Rimuovi Regola",
							msg: "Sei sicuro di voler rimuovere la regola \"" + this.selectedRule.title + "\"?",
							width: 300,
							buttons: Ext.Msg.YESNO,
							fn: function(buttonId, text) {
								if (buttonId == "yes") {
									Ext.data.StoreManager.lookup("rulesStore").removeAt(this.selectedRuleIndex);
									this.getDeleteRuleButton().disable();
									this.selectedRulePanel.removeAll();
									this.selectedRulePanel.setTitle("Regola");
									var rules = this.actualStyle.rules.splice(this.selectedRuleIndex, 1);
									this.fireEvent("ruleremoved", rules[0]);
								}
							},
							icon: Ext.Msg.QUESTION,
							scope: this
						});
					},
					scope: this
				}
			]
		});
		this.rulesPanel.on({
			select: function(rulesPanel, record, index) {
				this.selectedRule = record.get("rule");
				this.selectedRuleIndex = index;
				this.selectedRuleRecord = record;
				this.getDeleteRuleButton().enable();
				this.showRule(this.selectedRule);
				this.fireEvent("ruleselected", this.selectedRule);
			},
			scope: this
		});
		
		// Pannello con la definizione della regola (colori, spessori etc.)
		// Inizialmente � vuoto perch� ci viene caricato dentro in funzione del tipo di regola
		this.selectedRulePanel = Ext.create("Ext.Panel", {
			title: "Regola",
			region: 'center',
			autoScroll: true,
			width: 300
		});
		
		this.items = [
		    headPanel,
			this.rulesPanel,
			this.selectedRulePanel
		];
		
		this.btnSalva = Ext.create("Ext.button.Button",{
				text: "Salva",
				iconCls: "save",
				disabled: this.checkSaveDisabled(),
				handler: function() {
					
					this.styleRecord.set('name', this.nomeField.getValue());
			  		this.styleRecord.set('title', this.titoloField.getValue());
			  		//this.styleRecord.set('styleAbstract', this.descrizioneField.getValue());
			  		
			  	   
			    	//style['abstract'] = 'abstarct';
			  		this.actualStyle.title = this.titoloField.getValue();
			    	this.actualStyle.name = this.nomeField.getValue();
			  		
			  		this.styleRecord.set('sldtext',TolomeoExt.Styler.StylePanel.styleToSld(this.actualStyle));					
					this.fireEvent("stylesaved", this.styleRecord);
				},
				scope: this
			});
		
		this.bbar = [
			"->",
			{
				text: "Annulla",
				iconCls: "cancel",
				handler: function() {
					this.fireEvent("stylecanceled");
				},
				scope: this
			}, this.btnSalva
			
		];
		
		this.on("ruleadded", function() {
			this.btnSalva.setDisabled(false); 
		}, this);
		
		this.on("ruleremoved", function() {
			this.btnSalva.setDisabled(this.checkSaveDisabled()); 
		}, this);
		
		this.callParent();
	},
	
	
	aggiungiRegolaHandler: function(tipogenerazione, tipogeometria) {
		
		var s = null;
		switch (tipogeometria){
		case 1:
			s = new OpenLayers.Symbolizer.Point({
					pointRadius: 3,
					fillColor: '#FF0000',
					graphicName: 'circle'
				});
			break;
		case 2:
			s = new OpenLayers.Symbolizer.Line({
					strokeColor: '#FF0000'
				});
			break;
		case 3:
			s = new OpenLayers.Symbolizer.Polygon({
					strokeColor: '#FF0000',
					fillColor: '#FF0000'
				});
			break;
		}
		var rule = new OpenLayers.Rule({
			title: "Nuova regola",
			symbolizers: [s]
		});
		
		if (tipogenerazione==TolomeoExt.Styler.RuleGeneratorPanel.TIPOGENERAZIONE.SEMPLICE.codice) {
			this.addRule(s);
		} else {
			this.mostraFinestraGenerazioneStile(tipogenerazione, rule, null, null);
			
		}
		
		//layer
		
		
		
		
	},
	
	checkSaveDisabled: function() {
		return (this.actualStyle == null) || this.actualStyle.rules.length==0;
	
	},
	
	addRule: function(s) {
		
		var rule = new OpenLayers.Rule({
			title: "Nuova regola",
			symbolizers: [s]
		});
		if (this.actualStyle == null) {
			this.actualStyle = new OpenLayers.Style();
		}
		this.actualStyle.rules.push(rule);
		Ext.data.StoreManager.lookup("rulesStore").add({
			name: rule.title/*,
			symbol: Ext.create("TolomeoExt.Styler.FeatureRenderer", {
				symbolType: this.getSymbolTypeFromRule(rule),
				symbolizers: rule.symbolizers
			})*/,
			rule: rule
		});
		
		//this.showRule(rule);
		this.fireEvent("ruleadded");
		
	},
	
	showRule: function(rule) {
		this.selectedRulePanel.removeAll();
		this.selectedRulePanel.setTitle("Regola \"" + rule.title + "\"");
		var rulePanel = Ext.create("TolomeoExt.Styler.RulePanel", {
			autoHeight: false,
			autoScroll: true,
			rule: rule,
			nestedFilters: false,
			scaleLevels: (this.mapPanel) ? this.mapPanel.map.baseLayer.numZoomLevels : undefined,
			minScaleDenominatorLimit: (this.mapPanel) ? OpenLayers.Util.getScaleFromResolution(this.mapPanel.map.baseLayer.resolutions[this.mapPanel.map.baseLayer.numZoomLevels - 1], this.mapPanel.map.units) : undefined,
			maxScaleDenominatorLimit: (this.mapPanel) ? OpenLayers.Util.getScaleFromResolution(this.mapPanel.map.baseLayer.resolutions[0], this.mapPanel.map.units) : undefined,
			scaleSliderTemplate: "<div>{scaleType} Zoom Level: {zoom}</div>" + "<div>Current Map Zoom: {mapZoom}</div>",
			modifyScaleTipContext: Ext.Function.pass(function(panel, data) {
				if (this.mapPanel) {
					data.mapZoom = this.mapPanel.map.getZoom();
				}
			}, [], this),
			// TODO Recuperare campi effettivi
			attributes: Ext.create("Ext.data.Store", {
				model: "Field",
				data : [{
						name: "pippo"
					},
					{
						name: "pluto"
					},
					{
						name: "paperino"
					},
					{
						name: "cat"
					},
					{
						name: "str1"
					}
				]
			})
		});
		rulePanel.on('change', 
				function(rulePanel, rule) {
								if (this.selectedRuleRecord) {
									this.selectedRuleRecord.set('name', rule.title)
								}
							}, this);
		this.selectedRulePanel.add(rulePanel);
	},
	
	getAddRuleButton: function() {
		return this.rulesPanel.getDockedItems()[2].getComponent(0);
	},
	
	getDeleteRuleButton: function() {
		return this.rulesPanel.getDockedItems()[2].getComponent(1);
	},
	
	// Mostra la finestra per la creazione di una nuova stilizzazione non semplice
	// tipoCreazione - indica il tipo di creazione da eseguire (NB, EC, ER ..)
	// regola - rule vuota o di default da valorizzare (utilizzata per le caretteristiche base comuni)
	// symbolType - tipo di simbolo del livello selezionato (punto, linea poligono)
	// closeCallback - funzione di callback per la chiusura
	mostraFinestraGenerazioneStile : function(tipoCreazione, regola, symbolType, closeCallback) {
		var nuovaRule = (regola) ? regola.clone() : null;

		this.finestraGenerazioneStileDlg = new Ext.Window(
		{
			title : tipoCreazione.titoloFinestra,
			layout : "fit",
			width : 420,
			constrain : true,
			items : [ Ext.create('TolomeoExt.Styler.RuleGeneratorPanel', {
						rule : nuovaRule,	
						tipoCreazione: tipoCreazione,
						layer: this.layer,
						// TODO Recuperare campi effettivi
						attributes: Ext.create("Ext.data.Store", {
							model: "Field",
							data : [{ name: "CIRC"	},
								{
									name: "pluto"
								},
								{
									name: "paperino"
								},
								{
									name: "cat"
								},
								{
									name: "str1"
								}
							]
						}),
						autoHeight : false,
						autoScroll : true,
						symbolType : symbolType,
						nestedFilters : false,
						//TODO ALE scaleLevels : this.map.baseLayer.numZoomLevels,
						//TODO ALE minScaleLimit : OpenLayers.Util.getScaleFromResolution(this.map.baseLayer.resolutions[this.map.baseLayer.numZoomLevels - 1], this.map.units),
						//TODO ALE maxScaleLimit : OpenLayers.Util.getScaleFromResolution(this.map.baseLayer.resolutions[0], this.map.units),
						//TODO ALE minScaleDenominatorLimit: this.valoreMinScale,
						//TODO ALE maxScaleDenominatorLimit: this.valoreMaxScale,
						scaleSliderTemplate : "<div>{zoomType} Livello Zoom: {zoom}</div>" + "<div>Zoom Mappa Corrente: {mapZoom}</div>",
						listeners : {
							cancelPressed : function() {
								this.finestraGenerazioneStileDlg.close();
								//legenda.unselect();
								//this.getLegend().unselect();
								//if (closeCallback) {
								//	closeCallback.call(this);
								//}
							},
							/*move : function(cp, x, y) {
								this.windowPositions["finestraGenerazioneStileDlg"] = {
									x : x,
									y : y
								};
							},*/
							scope : this
						}
						
						
						
						//,
						// TODO ALE
						/* modifyScaleTipContext : (function(panel, data) {
							data.mapZoom = this.map.getZoom();
						}).createDelegate(this),
						attributes : new GeoExt.data.AttributeStore({
							url: stylesManagerUrl + "?url=" + layer.url.split("?")[0].replace('/wms', '/wfs') + '?',
							baseParams : {
								action: 'proxy',
								version : "1.1.1",
								request : "DescribeFeatureType",
								typeName : layer.params["LAYERS"]
							},
						ignore : { name : this.schemaManager.getFieldTypeToIgnore(layer) }
						}),*/
					}) ],
					/*
			bbar : [
					"->",
					{
						text : "Annulla",
						iconCls : "cancel",
						handler : function() {
							this.finestraGenerazioneStileDlg.close();
						},
						scope : this
					}, {
						text : "Genera",
						iconCls : "save",
						scope : this,
						handler : function() {
							Ext.getBody().mask('Elaborazione in corso...');

							this.rule = this.finestraGenerazioneStileDlg.items.items[0].rule.clone();
																
							new TolomeoExt.ToloCrossAjax().request({
								url: this.TOLOMEOServer + this.TOLOMEOContext + "/AjaxGeneraStiliServlet",
								method: 'POST',
								params: {
									//url: this.urlWFS,
									tipoGenerazione: tipoStilizzazioneRichiesta,
									precisione: precisioneDecimale,
									classi : numeroClassiTematizzazione,
									campo : nomeCampoTematizzazione,
									codTPN: this.layer.codTPN,
									// TODO
									//codice_comune: codiceComuneParamJsLocal,
									codice_comune: ""
								},
								failure : generaStiliFailure,
								success : generaStiliSuccess,
								scope : this
							});
						}
					} ],*/
			listeners : {
				close : function() {
					//legenda.unselect();
					//this.getLegend().unselect();
					//if (closeCallback) {
					//	closeCallback.call(this);
					//}
				},
				/*move : function(cp, x, y) {
					this.windowPositions["finestraGenerazioneStileDlg"] = {
						x : x,
						y : y
					};
				},*/
				scope : this
			}
		});
		this.finestraGenerazioneStileDlg.show();
	},
	
	generaStiliSuccess: function (results, store){
		
	/*
		var ajaxOptions = { method: 'post',
				url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxSpatialQueryServlet',
				params: {
					dtInizioFiltro: this.temporalFilterDtInizio,
					dtFineFiltro: this.temporalFilterDtFine,
					coordX: point.x, 
					coordY: point.y,
					codTPN: codTPN,
					range: tolleranceRange,
					SRID: this.paramsJS.mappe.SRID,
					format: 'ext',
					selectionMode: selectionMode,
					//Parametri aggiunti per GetFeatureInfo
					bbox:  bounds.left+","+bounds.bottom+","+bounds.right+","+bounds.top ,
					mapwidth:  this.viewer.pluginGetMapWidth()  ,
					mapheight: this.viewer.pluginGetMapViewerHeight() ,
					X: mapXPixel,
					Y: mapYPixel,
					additionalWMSLayers: (additionalWMSLayers && additionalWMSLayers.length > 0) ? Ext.JSON.encode(additionalWMSLayers) : undefined,
					paramPreset: this.paramsJS.nomePreset
				},
				success: function(results, store){this.ajaxQuerySelectOK(results, store, addToSelected, visualize);},
				failure: function(transport){
					this.fireEvent('selectRequestEnd',{
						ok:false,
						nResults:0,
						errText:transport.responseText?transport.responseText:""+transport
					});
					this.showAjaxError(transport);
				}, 
				scope: this
			}
			
			// Aggiunta parametri WMS da url
			Ext.apply(ajaxOptions.params, this.paramsJS.urlAdditionalParams);
					
			if(this.fireEvent('selectRequestBeforeStart')){
				new TolomeoExt.ToloCrossAjax().request(ajaxOptions);
				this.fireEvent('selectRequestStart');
				*/
		
		var classiGenerate;
		if(Ext.isEmpty(response.responseText)) return;
		else classiGenerate = Ext.decode(response.responseText);

		var panel = this.getLegend();													
		// Rimuovo le regole presenti											
		while(panel.rules.length > 0)
		{
			for ( var h = 0; h < panel.rules.length; h++) {
				panel.rules.remove(panel.rules[h]);		
				this.fireEvent("ruleremoved", panel.rules[h]);
			}
		}
		
		this.saving = true;
		this.finestraGenerazioneStileDlg.disable();
		// INIZIO - Per ogni classe generata
		var classeCorrente = 0;
		var trovataAlmenoUnaClasse = false;
		
		while(classiGenerate[classeCorrente] != null && classiGenerate[classeCorrente] != undefined)
		{	
			var nuovaRegola = this.rule.clone();
			
			var masterFilter = new OpenLayers.Filter.Logical();
			masterFilter.type  = classiGenerate[classeCorrente].tipofiltro;
			
			for(filtroCorrente in classiGenerate[classeCorrente].filtri)
			{
				var emptyFilter = new OpenLayers.Filter.Comparison();
				
				if(!Ext.isEmpty(classiGenerate[classeCorrente].filtri[filtroCorrente].valoreFiltro) &&
				   !Ext.isEmpty(classiGenerate[classeCorrente].filtri[filtroCorrente].tipoFiltro))
				{
					emptyFilter.value = classiGenerate[classeCorrente].filtri[filtroCorrente].valoreFiltro;
					emptyFilter.type  = classiGenerate[classeCorrente].filtri[filtroCorrente].tipoFiltro;
					emptyFilter.property = classiGenerate[classeCorrente].filtri[filtroCorrente].colonna;
					masterFilter.filters[filtroCorrente] = emptyFilter;
				}
			}

			if(panel.symbolType == "Line")
			{
				nuovaRegola.symbolizers[0].strokeColor = classiGenerate[classeCorrente].colore;
			}
			else
			{
				nuovaRegola.symbolizers[0].fillColor = classiGenerate[classeCorrente].colore;
			}
			nuovaRegola.name = classiGenerate[classeCorrente].nome;
			nuovaRegola.title = classiGenerate[classeCorrente].nome;
			nuovaRegola.filter = masterFilter;
			nuovaRegola.id =  "OpenLayers.Rule_" + classeCorrente;
			panel.rules.push(nuovaRegola);
			trovataAlmenoUnaClasse = true;
			classeCorrente = classeCorrente + 1;
			this.fireEvent("ruleadded", nuovaRegola);
		}// FINE - Per ogni classe generata

		if(!trovataAlmenoUnaClasse)
		{
			Ext.MessageBox.show({
				title: 'Errore',
				msg: "Impossibile generare delle classi per con le impostazioni correnti",
				buttons: Ext.MessageBox.OK,
				icon: Ext.MessageBox.ERROR
			});
			Ext.getBody().unmask();
			return;
		}
		
		this.sldManager.saveSld(this.currentLayer, function(){
			this.repaint();
		}, this);
				
		this.saving = false;
		
		this.repaint();
		panel.update();
		
		//this.currentLayer.display(false);
		//this.currentLayer.clearGrid();
		//this.currentLayer.mergeNewParams({'random':Math.random()});
		//this.currentLayer.redraw(true);
		//this.currentLayer.display(true);
		
		if(this.finestraGenerazioneStileDlg)
		{
			this.finestraGenerazioneStileDlg.close();
			this.finestraGenerazioneStileDlg.destroy();
		}
		
		
	},
	
	generaStiliFailure: function (){
		Ext.MessageBox.show({
			title: 'Errore',
			msg: "Errore nella generazione della stilizzazione",
			buttons: Ext.MessageBox.OK,
			icon: Ext.MessageBox.ERROR
		});
	}
	
	
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.StrokeSymbolizer", {
	extend: "Ext.FormPanel",
	alias: "widget.styler_strokesymbolizer",
	symbolizer: null,
	colorManager: null,
	checkboxToggle: true,
	defaultColor: null,
	withColor: true, 
	dashStyles: [{
		value: "solid",
		display: "solid"
	}, {
		value: "4 4",
		display: "dash"
	},{
		value: "2 4",
		display: "dot"
	}],
	border: false,
	initComponent: function() {
		if (!this.symbolizer) {
			this.symbolizer = {};
		}
		var colorFieldPlugins;
		if (this.colorManager) {
			colorFieldPlugins = [new this.colorManager];
		}
		this.items = [{
			xtype: "fieldset",
			title: "Tratto",
			autoHeight: true,
			checkboxToggle: this.checkboxToggle,
			collapsed: this.checkboxToggle === true && this.symbolizer.stroke === false,
			hideMode: "offsets",
			defaults: {
				width: 200
			},
			items: [{
				xtype: "combo",
				name: "style",
				fieldLabel: "Stile",
				store: Ext.create("Ext.data.JsonStore", {
					data: this.dashStyles,
					fields: ["value", "display"]
				}),
				displayField: "display",
				valueField: "value",
				value: this.getDashArray(this.symbolizer.strokeDashstyle) || TolomeoExt.Styler.Renderer.DefaultSymbolizer.strokeDashstyle,
				queryMode: "local",
				allowBlank: true,
				triggerAction: "all",
				editable: false,
				listeners: {
					select: function(combo, record) {
						this.symbolizer.strokeDashstyle = record[0].get("value");
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				xtype: "styler_colorfield",
				name: "color",
				fieldLabel: "Colore",
				hidden: !this.withColor, 
				emptyText: TolomeoExt.Styler.Renderer.DefaultSymbolizer.strokeColor,
				value: this.symbolizer.strokeColor || this.defaultColor || TolomeoExt.Styler.Renderer.DefaultSymbolizer.strokeColor,
				defaultBackground: this.defaultColor || TolomeoExt.Styler.Renderer.DefaultSymbolizer.strokeColor,
				plugins: colorFieldPlugins,
				listeners: {
					change: function(field, newValue, oldValue) {
						this.symbolizer.strokeColor = newValue;
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				xtype: "numberfield",
				name: "width",
				fieldLabel: "Spessore",
				minValue: 0,
				emptyText: TolomeoExt.Styler.Renderer.DefaultSymbolizer.strokeWidth,
				value: this.symbolizer.strokeWidth || TolomeoExt.Styler.Renderer.DefaultSymbolizer.strokeWidth,
				listeners: {
					change: function(field, value) {
						value = parseFloat(value);
						if (isNaN(value)) {
							delete this.symbolizer.strokeWidth;
						} else {
							this.symbolizer.strokeWidth = value;
						}
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				xtype: "slider",
				name: "opacity",
				fieldLabel: "Opacit&agrave;",
				values: [
					(("strokeOpacity" in this.symbolizer) ? this.symbolizer.strokeOpacity : TolomeoExt.Styler.Renderer.DefaultSymbolizer.strokeOpacity) * 100
				],
				isFormField: true,
				listeners: {
					changecomplete: function(slider, value) {
						this.symbolizer.strokeOpacity = value / 100;
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				},
				tipText: function(thumb) {
					return thumb.value + "%";
				}
			}],
			listeners: {
				"collapse": function() {
					if (this.symbolizer.stroke !== false) {
						this.symbolizer.stroke = false;
						this.fireEvent("change", this.symbolizer);
					}
				},
				"expand": function() {
					this.symbolizer.stroke = true;
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			}
		}];
		this.addEvents("change");
		TolomeoExt.Styler.StrokeSymbolizer.superclass.initComponent.call(this);
	},
	getDashArray: function(style) {
		var array;
		if (style) {
			var parts = style.split(/\s+/);
			var ratio = parts[0] / parts[1];
			var array;
			if (!isNaN(ratio)) {
				array = ratio >= 1 ? "4 4" : "2 4"
			}
		}
		return array;
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.FillSymbolizer", {
	extend: "Ext.FormPanel",
	alias: "widget.styler_fillsymbolizer",
	symbolizer: null,
	colorManager: null,
	checkboxToggle: true,
	defaultColor: null,
	withColor: true, 
	border: false,
	initComponent: function() {
		if (!this.symbolizer) {
			this.symbolizer = {};
		}
		var colorFieldPlugins;
		if (this.colorManager) {
			colorFieldPlugins = [new this.colorManager];
		}
		this.items = [{
			xtype: "fieldset",
			title: "Riempimento",
			autoHeight: true,
			checkboxToggle: this.checkboxToggle,
			collapsed: this.checkboxToggle === true && this.symbolizer.fill === false,
			hideMode: "offsets",
			defaults: {
				width: 200
			},
			items: [{
				xtype: "styler_colorfield",
				fieldLabel: "Colore",
				hidden: !this.withColor, 
				name: "color",
				emptyText: TolomeoExt.Styler.Renderer.DefaultSymbolizer.fillColor,
				value: this.symbolizer.fillColor || this.defaultColor || TolomeoExt.Styler.Renderer.DefaultSymbolizer.fillColor,
				defaultBackground: this.defaultColor || TolomeoExt.Styler.Renderer.DefaultSymbolizer.fillColor,
				plugins: colorFieldPlugins,
				listeners: {
					change: function(field, newValue, oldValue) {
						this.symbolizer.fillColor = newValue;
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				xtype: "slider",
				fieldLabel: "Opacit&agrave;",
				name: "opacity",
				values: [
					(("fillOpacity" in this.symbolizer) ? this.symbolizer.fillOpacity : TolomeoExt.Styler.Renderer.DefaultSymbolizer.fillOpacity) * 100
				],
				isFormField: true,
				listeners: {
					changecomplete: function(slider, value) {
						this.symbolizer.fillOpacity = value / 100;
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				},
				tipText: function(thumb) {
					return thumb.value + "%";
				}
			}],
			listeners: {
				"collapse": function() {
					if (this.symbolizer.fill !== false) {
						this.symbolizer.fill = false;
						this.fireEvent("change", this.symbolizer);
					}
				},
				"expand": function() {
					this.symbolizer.fill = true;
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			}
		}];
		this.addEvents("change");
		TolomeoExt.Styler.FillSymbolizer.superclass.initComponent.call(this);
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.TextSymbolizer", {
	extend: "Ext.Panel",
	alias: "widget.styler_textsymbolizer",
	fonts: undefined,
	symbolizer: null,
	defaultSymbolizer: null,
	attributes: null,
	colorManager: null,
	haloCache: null,
	border: false,
	layout: "form",
	initComponent: function() {
		if (!this.symbolizer) {
			this.symbolizer = {};
		}
		Ext.applyIf(this.symbolizer, this.defaultSymbolizer);
		this.haloCache = {};
		var defAttributesComboConfig = {
			xtype: "combo",
			fieldLabel: "Valori Etichetta",
			store: this.attributes,
			editable: false,
			triggerAction: "all",
			allowBlank: false,
			displayField: "name",
			valueField: "name",
			queryMode: "local",
			value: this.symbolizer.label && this.symbolizer.label.replace(/^\${(.*)}$/, "$1"),
			listeners: {
				select: function(combo, record) {
					this.symbolizer.label = "${" + record[0].get("name") + "}";
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			},
			width: 120
		};
		this.attributesComboConfig = this.attributesComboConfig || {};
		Ext.applyIf(this.attributesComboConfig, defAttributesComboConfig);
		this.labelWidth = 80;
		this.items = [this.attributesComboConfig, {
			cls: "x-html-editor-tb",
			style: "background: transparent; border: none; padding: 0 0em 0.5em;",
			xtype: "toolbar",
			items: [{
				xtype: "styler_fontcombo",
				fonts: this.fonts || undefined,
				width: 110,
				value: this.symbolizer.fontFamily,
				listeners: {
					select: function(combo, record) {
						this.symbolizer.fontFamily = record.get("field1");
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				xtype: "numberfield",
				fieldLabel: "Dimensione",
				labelWidth: 30,
				minValue: 0,
				emptyText: TolomeoExt.Styler.Renderer.DefaultSymbolizer.fontSize,
				value: this.symbolizer.fontSize || TolomeoExt.Styler.Renderer.DefaultSymbolizer.fontSize,
				width: 80,
				listeners: {
					change: function(field, value) {
						value = parseFloat(value);
						if (isNaN(value)) {
							delete this.symbolizer.fontSize;
						} else {
							this.symbolizer.fontSize = value;
						}
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				enableToggle: true,
				cls: "x-btn-icon",
				iconCls: "x-edit-bold",
				pressed: this.symbolizer.fontWeight === "bold",
				listeners: {
					toggle: function(button, pressed) {
						this.symbolizer.fontWeight = pressed ? "bold" : "normal";
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				enableToggle: true,
				cls: "x-btn-icon",
				iconCls: "x-edit-italic",
				pressed: this.symbolizer.fontStyle === "italic",
				listeners: {
					toggle: function(button, pressed) {
						this.symbolizer.fontStyle = pressed ? "italic" : "normal";
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}]
		}, {
			xtype: "styler_fillsymbolizer",
			symbolizer: this.symbolizer,
			defaultColor: TolomeoExt.Styler.Renderer.DefaultSymbolizer.fontColor,
			checkboxToggle: false,
			autoHeight: true,
			labelWidth: 70,
			plugins: this.colorManager && [new this.colorManager()],
			listeners: {
				change: function(symbolizer) {
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			}
		}, {
			xtype: "fieldset",
			title: "Alone",
			checkboxToggle: true,
			collapsed: !(this.symbolizer.haloRadius || this.symbolizer.haloColor || this.symbolizer.haloOpacity),
			autoHeight: true,
			labelWidth: 50,
			items: [{
				xtype: "numberfield",
				fieldLabel: "Size",
				anchor: "89%",
				minValue: 0,
				emptyText: TolomeoExt.Styler.Renderer.DefaultSymbolizer.haloRadius,
				value: this.symbolizer.haloRadius || TolomeoExt.Styler.Renderer.DefaultSymbolizer.haloRadius,
				listeners: {
					change: function(field, value) {
						value = parseFloat(value);
						if (isNaN(value)) {
							delete this.symbolizer.haloRadius;
						} else {
							this.symbolizer.haloRadius = value;
						}
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				xtype: "styler_fillsymbolizer",
				symbolizer: {
					fillColor: ("haloColor" in this.symbolizer) ? this.symbolizer.haloColor : TolomeoExt.Styler.Renderer.DefaultSymbolizer.haloColor,
					fillOpacity: ("haloOpacity" in this.symbolizer) ? this.symbolizer.haloOpacity : TolomeoExt.Styler.Renderer.DefaultSymbolizer.haloOpacity
				},
				defaultColor: TolomeoExt.Styler.Renderer.DefaultSymbolizer.haloColor,
				checkboxToggle: false,
				labelWidth: 60,
				plugins: this.colorManager && [new this.colorManager()],
				listeners: {
					change: function(symbolizer) {
						this.symbolizer.haloColor = symbolizer.fillColor;
						this.symbolizer.haloOpacity = symbolizer.fillOpacity;
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}],
			listeners: {
				collapse: function() {
					this.haloCache = {
						haloRadius: this.symbolizer.haloRadius,
						haloColor: this.symbolizer.haloColor,
						haloOpacity: this.symbolizer.haloOpacity
					};
					delete this.symbolizer.haloRadius;
					delete this.symbolizer.haloColor;
					delete this.symbolizer.haloOpacity;
					this.fireEvent("change", this.symbolizer)
				},
				expand: function() {
					Ext.apply(this.symbolizer, this.haloCache);
					this.doLayout();
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			}
		}];
		this.addEvents("change");
		TolomeoExt.Styler.TextSymbolizer.superclass.initComponent.call(this);
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.ScaleLimitPanel", {
	extend: "Ext.Panel",
	alias: "widget.styler_scalelimitpanel",
	maxScaleDenominatorLimit: 40075016.68 * 39.3701 * OpenLayers.DOTS_PER_INCH / 256,
	limitMaxScaleDenominator: true,
	maxScaleDenominator: undefined,
	minScaleDenominatorLimit: Math.pow(0.5, 19) * 40075016.68 * 39.3701 * OpenLayers.DOTS_PER_INCH / 256,
	limitMinScaleDenominator: true,
	minScaleDenominator: undefined,
	scaleLevels: 20,
	scaleSliderTemplate: "{scaleType} Scale 1:{scale}",
	modifyScaleTipContext: Ext.emptyFn,
	scaleFactor: null,
	changing: false,
	border: false,
	initComponent: function() {
		this.layout = "column";
		this.defaults = {
			border: false,
			bodyStyle: "margin: 0 5px;"
		};
		this.bodyStyle = {
			padding: "5px"
		};
		this.scaleSliderTemplate = new Ext.Template(this.scaleSliderTemplate);
		Ext.applyIf(this, {
			minScaleDenominator: this.minScaleDenominatorLimit,
			maxScaleDenominator: this.maxScaleDenominatorLimit
		});
		this.scaleFactor = Math.pow(this.maxScaleDenominatorLimit / this.minScaleDenominatorLimit, 1 / (this.scaleLevels - 1));
		this.scaleSlider = Ext.create("Ext.Slider", {
			vertical: true,
			height: 100,
			values: [0, 100],
			listeners: {
				changecomplete: function(slider, value) {
					this.updateScaleValues(slider);
				},
				render: function(slider) {
					slider.thumbs[0].el.setVisible(this.limitMaxScaleDenominator);
					slider.thumbs[1].el.setVisible(this.limitMinScaleDenominator);
					slider.setDisabled(!this.limitMinScaleDenominator && !this.limitMaxScaleDenominator);
				},
				scope: this
			},
			plugins: [Ext.create("TolomeoExt.Styler.slider.Tip", {
				getText: Ext.Function.pass(function(thumb) {
					var index = thumb.slider.thumbs.indexOf(thumb);
					var value = thumb.value;
					var scales = this.sliderValuesToScale([thumb.value]);
					var data = {
						scale: String(scales[0]),
						zoom: (thumb.value * (this.scaleLevels / 100)).toFixed(1),
						type: (index === 0) ? "Max" : "Min",
						scaleType: (index === 0) ? "Min" : "Max"
					};
					this.modifyScaleTipContext(this, data);
					return this.scaleSliderTemplate.apply(data);
				}, [], this)
			})]
		});
		this.maxScaleDenominatorInput = Ext.create("Ext.form.NumberField", {
			minValue: 0,
			width: 100,
			fieldLabel: "1",
			value: Math.round(this.maxScaleDenominator),
			disabled: !this.limitMaxScaleDenominator,
			validator: Ext.Function.pass(function(value) {
				return !this.limitMinScaleDenominator || (value > this.minScaleDenominator);
			}, [], this),
			listeners: {
				valid: function(field) {
					var value = Number(field.getValue());
					var limit = Math.round(this.maxScaleDenominatorLimit);
					if (value < limit && value > this.minScaleDenominator) {
						this.maxScaleDenominator = value;
						this.updateSliderValues();
					}
				},
				change: function(field) {
					var value = Number(field.getValue());
					var limit = Math.round(this.maxScaleDenominatorLimit);
					if (value > limit) {
						field.setValue(limit);
					} else if (value < this.minScaleDenominator) {
						field.setValue(this.minScaleDenominator);
					} else {
						this.maxScaleDenominator = value;
						this.updateSliderValues();
					}
				},
				scope: this
			}
		});
		this.minScaleDenominatorInput = Ext.create("Ext.form.NumberField", {
			minValue: 0,
			width: 100,
			fieldLabel: "1",
			value: Math.round(this.minScaleDenominator),
			disabled: !this.limitMinScaleDenominator,
			validator: Ext.Function.pass(function(value) {
				return !this.limitMaxScaleDenominator || (value < this.maxScaleDenominator);
			}, [], this),
			listeners: {
				valid: function(field) {
					var value = Number(field.getValue());
					var limit = Math.round(this.minScaleDenominatorLimit);
					if (value > limit && value < this.maxScaleDenominator) {
						this.minScaleDenominator = value;
						this.updateSliderValues();
					}
				},
				change: function(field) {
					var value = Number(field.getValue());
					var limit = Math.round(this.minScaleDenominatorLimit);
					if (value < limit) {
						field.setValue(limit);
					} else if (value > this.maxScaleDenominator) {
						field.setValue(this.maxScaleDenominator);
					} else {
						this.minScaleDenominator = value;
						this.updateSliderValues();
					}
				},
				scope: this
			}
		});
		this.items = [this.scaleSlider, {
			xtype: "panel",
			layout: "form",
			defaults: {
				border: false
			},
			items: [{
				labelWidth: 90,
				layout: "form",
				width: 150,
				items: [{
					xtype: "checkbox",
					checked: !!this.limitMinScaleDenominator,
					fieldLabel: "Limite di Scala Massimo",
					listeners: {
						change: function(box, newValue, oldValue) {
							this.limitMinScaleDenominator = newValue;
							var slider = this.scaleSlider;
							slider.setValue(1, 100);
							slider.thumbs[1].el.setVisible(newValue);
							this.minScaleDenominatorInput.setDisabled(!newValue);
							this.updateScaleValues(slider);
							slider.setDisabled(!this.limitMinScaleDenominator && !this.limitMaxScaleDenominator);
						},
						scope: this
					}
				}]
			}, {
				labelWidth: 10,
				layout: "form",
				items: [this.minScaleDenominatorInput]
			}, {
				labelWidth: 90,
				layout: "form",
				items: [{
					xtype: "checkbox",
					checked: !!this.limitMaxScaleDenominator,
					fieldLabel: "Limite di Scala Minimo",
					listeners: {
						change: function(box, newValue, oldValue) {
							this.limitMaxScaleDenominator = newValue;
							var slider = this.scaleSlider;
							slider.setValue(0, 0);
							slider.thumbs[0].el.setVisible(newValue);
							this.maxScaleDenominatorInput.setDisabled(!newValue);
							this.updateScaleValues(slider);
							slider.setDisabled(!this.limitMinScaleDenominator && !this.limitMaxScaleDenominator);
						},
						scope: this
					}
				}]
			}, {
				labelWidth: 10,
				layout: "form",
				items: [this.maxScaleDenominatorInput]
			}]
		}];
		this.addEvents("change");
		TolomeoExt.Styler.ScaleLimitPanel.superclass.initComponent.call(this);
	},
	updateScaleValues: function(slider) {
		if (!this.changing) {
			var values = slider.getValues();
			var resetSlider = false;
			if (!this.limitMaxScaleDenominator) {
				if (values[0] > 0) {
					values[0] = 0;
					resetSlider = true;
				}
			}
			if (!this.limitMinScaleDenominator) {
				if (values[1] < 100) {
					values[1] = 100;
					resetSlider = true;
				}
			}
			if (resetSlider) {
				slider.setValue(0, values[0]);
				slider.setValue(1, values[1]);
			} else {
				var scales = this.sliderValuesToScale(values);
				var max = scales[0];
				var min = scales[1];
				this.changing = true;
				this.minScaleDenominatorInput.setValue(min);
				this.maxScaleDenominatorInput.setValue(max);
				this.changing = false;
				this.fireEvent("change", this, (this.limitMinScaleDenominator) ? min : undefined, (this.limitMaxScaleDenominator) ? max : undefined);
			}
		}
	},
	updateSliderValues: function() {
		if (!this.changing) {
			var min = this.minScaleDenominator;
			var max = this.maxScaleDenominator;
			var values = this.scaleToSliderValues([max, min]);
			this.changing = true;
			this.scaleSlider.setValue(0, values[0]);
			this.scaleSlider.setValue(1, values[1]);
			this.changing = false;
			this.fireEvent("change", this, (this.limitMinScaleDenominator) ? min : undefined, (this.limitMaxScaleDenominator) ? max : undefined);
		}
	},
	sliderValuesToScale: function(values) {
		var interval = 100 / (this.scaleLevels - 1);
		return [Math.round(Math.pow(this.scaleFactor, (100 - values[0]) / interval) * this.minScaleDenominatorLimit), Math.round(Math.pow(this.scaleFactor, (100 - values[1]) / interval) * this.minScaleDenominatorLimit)];
	},
	scaleToSliderValues: function(scales) {
		var interval = 100 / (this.scaleLevels - 1);
		return [100 - (interval * Math.log(scales[0] / this.minScaleDenominatorLimit) / Math.log(this.scaleFactor)), 100 - (interval * Math.log(scales[1] / this.minScaleDenominatorLimit) / Math.log(this.scaleFactor))];
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.PointSymbolizer", {
	extend: "Ext.Panel",
	alias: "widget.styler_pointsymbolizer",
	symbolizer: null,
	withColor: true,
	pointGraphics: null,
	colorManager: null,
	external: null,
	layout: "form",
	initComponent: function() {
		
		//Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);

		if (this.pointGraphics==null) {
			this.pointGraphics = [{
				value: "circle",
				display: "circle",
				preview:  this.TOLOMEOServer + this.TOLOMEOStaticRoot + "img/styler/circle.gif",
				mark: true
			}, {
				value: "square",
				display: "square",
				preview: this.TOLOMEOServer + this.TOLOMEOStaticRoot + "img/styler/square.gif",
				mark: true
			}, {
				value: "triangle",
				display: "triangle",
				preview: this.TOLOMEOServer + this.TOLOMEOStaticRoot + "img/styler/triangle.gif",
				mark: true
			}, {
				value: "star",
				display: "star",
				preview: this.TOLOMEOServer + this.TOLOMEOStaticRoot + "img/styler/star.gif",
				mark: true
			}, {
				value: "cross",
				display: "cross",
				preview: this.TOLOMEOServer + this.TOLOMEOStaticRoot + "img/styler/cross.gif",
				mark: true
			}, {
				value: "x",
				display: "x",
				preview: this.TOLOMEOServer + this.TOLOMEOStaticRoot + "img/styler/x.gif",
				mark: true
			}, {
				display: "external"
			}]	
		}
			
		if (!this.symbolizer) {
			this.symbolizer = {};
		}
		this.external = !!this.symbolizer["externalGraphic"];
		this.markPanel = Ext.create("Ext.Panel", {
			border: false,
			collapsed: this.external,
			layout: "form",
			items: [{
				xtype: "styler_fillsymbolizer",
				symbolizer: this.symbolizer,
				withColor: this.withColor, 
				labelWidth: this.labelWidth,
				labelAlign: this.labelAlign,
				colorManager: this.colorManager,
				listeners: {
					change: function(symbolizer) {
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}, {
				xtype: "styler_strokesymbolizer",
				symbolizer: this.symbolizer,
				withColor: this.withColor, 
				labelWidth: this.labelWidth,
				labelAlign: this.labelAlign,
				colorManager: this.colorManager,
				listeners: {
					change: function(symbolizer) {
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				}
			}]
		});
		this.urlField = Ext.create("Ext.form.TextField", {
			name: "url",
			fieldLabel: "URL",
			value: this.symbolizer["externalGraphic"],
			hidden: true,
			listeners: {
				change: function(field, value) {
					this.symbolizer["externalGraphic"] = value;
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			},
			width: 100
		});
		this.graphicPanel = Ext.create("Ext.Panel", {
			border: false,
			collapsible: true,
			collapsed: !this.external,
			layout: "form",
			items: [this.urlField, {
				xtype: "slider",
				name: "opacity",
				fieldLabel: "Opacit&agrave;",
				values: [
					(this.symbolizer["graphicOpacity"] == null) ? 100 : this.symbolizer["graphicOpacity"] * 100
				],
				isFormField: true,
				listeners: {
					changecomplete: function(slider, value) {
						this.symbolizer["graphicOpacity"] = value / 100;
						this.fireEvent("change", this.symbolizer);
					},
					scope: this
				},
				tipText: function(thumb) {
					return thumb.value + "%";
				},
				width: 100
			}]
		});
		this.items = [{
			xtype: "combo",
			name: "mark",
			fieldLabel: "Simbolo",
			store: Ext.create("Ext.data.JsonStore", {
				data: this.pointGraphics,
				fields: ["value", "display", "preview", {
					name: "mark",
					type: "boolean"
				}]
			}),
			value: this.external ? 0 : this.symbolizer["graphicName"],
			displayField: "display",
			valueField: "value",
			tpl: new Ext.XTemplate(
				'<tpl for=".">',
					'<div class="x-boundlist-item x-combo-list-item gx-pointsymbolizer-mark-item">',
						'<tpl if="preview">',
							'<img src="{preview}" alt="{display}"/>',
						'</tpl>',
						'<span>{display}</span>',
					'</div>',
				'</tpl>'
			),
			queryMode: "local",
			allowBlank: false,
			triggerAction: "all",
			editable: false,
			listeners: {
				select: function(combo, records) {
					var mark = records[0].get("mark");
					var value = records[0].get("value");
					if (!mark) {
						if (value) {
							this.urlField.hide();
							this.urlField.getEl().up('.x-form-item').setDisplayed(false);
							this.symbolizer["externalGraphic"] = value;
						} else {
							this.urlField.show();
							this.urlField.getEl().up('.x-form-item').setDisplayed(true);
						}
						if (!this.external) {
							this.external = true;
							this.updateGraphicDisplay();
						}
					} else {
						if (this.external) {
							this.external = false;
							delete this.symbolizer["externalGraphic"];
							this.updateGraphicDisplay();
						}
						this.symbolizer["graphicName"] = value;
					}
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			},
			width: 100
		}, {
			xtype: "textfield",
			name: "size",
			fieldLabel: "Size",
			value: this.symbolizer["pointRadius"] && this.symbolizer["pointRadius"] * 2,
			listeners: {
				change: function(field, value) {
					this.symbolizer["pointRadius"] = value / 2;
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			},
			width: 100
		}, {
			xtype: "textfield",
			name: "rotation",
			fieldLabel: "Rotazione",
			value: this.symbolizer["rotation"] || TolomeoExt.Styler.Renderer.DefaultSymbolizer.pointRotation,
			listeners: {
				change: function(field, value) {
					this.symbolizer["rotation"] = value;
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			},
			width: 100
		}, this.markPanel, this.graphicPanel];
		this.addEvents("change");
		TolomeoExt.Styler.PointSymbolizer.superclass.initComponent.call(this);
	},
	updateGraphicDisplay: function() {
		if (this.external) {
			this.markPanel.collapse();
			this.graphicPanel.expand();
		} else {
			this.graphicPanel.collapse();
			this.markPanel.expand();
		}
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.LineSymbolizer", {
	extend: "Ext.Panel",
	alias: "widget.styler_linesymbolizer",
	symbolizer: null,
	withColor: true, 
	initComponent: function() {
		this.items = [{
			xtype: "styler_strokesymbolizer",
			symbolizer: this.symbolizer,
			withColor: this.withColor, 
			listeners: {
				change: function(symbolizer) {
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			}
		}];
		this.addEvents("change");
		TolomeoExt.Styler.LineSymbolizer.superclass.initComponent.call(this);
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.PolygonSymbolizer", {
	extend: "Ext.Panel",
	alias: "widget.styler_polygonsymbolizer",
	symbolizer: null,
	withColor: true,
	initComponent: function() {
		this.items = [{
			xtype: "styler_fillsymbolizer",
			symbolizer: this.symbolizer,
			withColor: this.withColor, 
			listeners: {
				change: function(symbolizer) {
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			}
		}, {
			xtype: "styler_strokesymbolizer",
			symbolizer: this.symbolizer,
			withColor: this.withColor, 
			listeners: {
				change: function(symbolizer) {
					this.fireEvent("change", this.symbolizer);
				},
				scope: this
			}
		}];
		this.addEvents("change");
		TolomeoExt.Styler.PolygonSymbolizer.superclass.initComponent.call(this);
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.FilterBuilder", {
	extend: "Ext.Container",
	alias: "widget.styler_filterbuilder",
	statics: {
		ANY_OF: 0,
		ALL_OF: 1,
		NONE_OF: 2,
		NOT_ALL_OF: 3
	},
	builderTypeNames: ["any", "all", "none", "not all"],
	allowedBuilderTypes: null,
	preComboText: "Corrisponde",
	postComboText: "del seguente:",
	cls: "gx-filterbuilder",
	builderType: null,
	childFilterContainer: null,
	customizeFilterOnInit: true,
	allowGroups: true,
	initComponent: function() {
		var defConfig = {
			defaultBuilderType: TolomeoExt.Styler.FilterBuilder.ANY_OF
		};
		Ext.applyIf(this, defConfig);
		if (this.customizeFilterOnInit) {
			this.filter = this.customizeFilter(this.filter);
		}
		this.builderType = this.getBuilderType();
		this.items = [{
			xtype: "container",
			layout: "form",
			defaults: {
				anchor: "100%"
			},
			hideLabels: true,
			items: [{
				xtype: "fieldcontainer",
				style: "padding-left: 2px",
				items: [{
					xtype: "label",
					style: "padding-top: 0.3em",
					text: this.preComboText
				}, this.createBuilderTypeCombo(), {
					xtype: "label",
					style: "padding-top: 0.3em",
					text: this.postComboText
				}]
			}, this.createChildFiltersPanel(), {
				xtype: "toolbar",
				items: this.createToolBar()
			}]
		}];
		this.addEvents("change");
		TolomeoExt.Styler.FilterBuilder.superclass.initComponent.call(this);
	},
	createToolBar: function() {
		var bar = [{
			text: "Aggiungi Condizione",
			iconCls: "add",
			handler: function() {
				this.addCondition();
			},
			scope: this
		}];
		if (this.allowGroups) {
			bar.push({
				text: "add group",
				iconCls: "add",
				handler: function() {
					this.addCondition(true);
				},
				scope: this
			});
		}
		return bar;
	},
	getFilter: function() {
		var filter;
		if (this.filter) {
			filter = this.filter.clone();
			if (filter instanceof OpenLayers.Filter.Logical) {
				filter = this.cleanFilter(filter);
			}
		}
		return filter;
	},
	cleanFilter: function(filter) {
		if (filter instanceof OpenLayers.Filter.Logical) {
			if (filter.type !== OpenLayers.Filter.Logical.NOT && filter.filters.length === 1) {
				filter = this.cleanFilter(filter.filters[0]);
			} else {
				var child;
				for (var i = 0, len = filter.filters.length; i < len; ++i) {
					child = filter.filters[i];
					if (child instanceof OpenLayers.Filter.Logical) {
						child = this.cleanFilter(child);
						if (child) {
							filter.filters[i] = child;
						} else {
							filter = child;
							break;
						}
					} else if (!child || child.type === null || child.property === null || child.value === null) {
						filter = false;
						break;
					}
				}
			}
		} else {
			if (!filter || filter.type === null || filter.property === null || filter.value === null) {
				filter = false;
			}
		}
		return filter;
	},
	customizeFilter: function(filter) {
		if (!filter) {
			filter = this.wrapFilter(this.createDefaultFilter());
		} else {
			filter = this.cleanFilter(filter);
			switch (filter.type) {
				case OpenLayers.Filter.Logical.AND:
				case OpenLayers.Filter.Logical.OR:
					if (!filter.filters || filter.filters.length === 0) {
						filter.filters = [this.createDefaultFilter()];
					} else {
						var child;
						for (var i = 0, len = filter.filters.length; i < len; ++i) {
							child = filter.filters[i];
							if (child instanceof OpenLayers.Filter.Logical) {
								filter.filters[i] = this.customizeFilter(child);
							}
						}
					}
					filter = new OpenLayers.Filter.Logical({
						type: OpenLayers.Filter.Logical.OR,
						filters: [filter]
					});
					break;
				case OpenLayers.Filter.Logical.NOT:
					if (!filter.filters || filter.filters.length === 0) {
						filter.filters = [new OpenLayers.Filter.Logical({
							type: OpenLayers.Filter.Logical.OR,
							filters: [this.createDefaultFilter()]
						})];
					} else {
						var child = filter.filters[0];
						if (child instanceof OpenLayers.Filter.Logical) {
							if (child.type !== OpenLayers.Filter.Logical.NOT) {
								var grandchild;
								for (var i = 0, len = child.filters.length; i < len; ++i) {
									grandchild = child.filters[i];
									if (grandchild instanceof OpenLayers.Filter.Logical) {
										child.filters[i] = this.customizeFilter(grandchild);
									}
								}
							} else {
								if (child.filters && child.filters.length > 0) {
									filter = this.customizeFilter(child.filters[0]);
								} else {
									filter = this.wrapFilter(this.createDefaultFilter());
								}
							}
						} else {
							var type;
							if (this.defaultBuilderType === TolomeoExt.Styler.FilterBuilder.NOT_ALL_OF) {
								type = OpenLayers.Filter.Logical.AND;
							} else {
								type = OpenLayers.Filter.Logical.OR;
							}
							filter.filters = [new OpenLayers.Filter.Logical({
								type: type,
								filters: [child]
							})];
						}
					}
					break;
				default:
					filter = this.wrapFilter(filter);
			}
		}
		return filter;
	},
	createDefaultFilter: function() {
		return new OpenLayers.Filter.Comparison();
	},
	wrapFilter: function(filter) {
		var type;
		if (this.defaultBuilderType === TolomeoExt.Styler.FilterBuilder.ALL_OF) {
			type = OpenLayers.Filter.Logical.AND;
		} else {
			type = OpenLayers.Filter.Logical.OR;
		}
		return new OpenLayers.Filter.Logical({
			type: OpenLayers.Filter.Logical.OR,
			filters: [new OpenLayers.Filter.Logical({
				type: type,
				filters: [filter]
			})]
		});
	},
	addCondition: function(group) {
		var filter, type;
		if (group) {
			type = "styler_filterbuilder";
			filter = this.wrapFilter(this.createDefaultFilter());
		} else {
			type = "styler_filterfield";
			filter = this.createDefaultFilter();
		}
		var newChild = this.newRow({
			xtype: type,
			filter: filter,
			columnWidth: 1,
			attributes: this.attributes,
			customizeFilterOnInit: group && false,
			listeners: {
				change: function() {
					this.fireEvent("change", this);
				},
				scope: this
			}
		});
		this.childFilterContainer.add(newChild);
		this.filter.filters[0].filters.push(filter);
		this.childFilterContainer.doLayout();
	},
	removeCondition: function(item, filter) {
		var parent = this.filter.filters[0].filters;
		if (parent.length > 1) {
			this.childFilterContainer.remove(item, true);
		}
		this.fireEvent("change", this);
	},
	createBuilderTypeCombo: function() {
		var types = this.allowedBuilderTypes || [TolomeoExt.Styler.FilterBuilder.ANY_OF, TolomeoExt.Styler.FilterBuilder.ALL_OF, TolomeoExt.Styler.FilterBuilder.NONE_OF];
		var numTypes = types.length;
		var data = new Array(numTypes);
		var type;
		for (var i = 0; i < numTypes; ++i) {
			type = types[i];
			data[i] = {value: type, name: this.builderTypeNames[type]};
		}
		return {
			xtype: "combo",
			store: Ext.create("Ext.data.JsonStore", {
				data: data,
				fields: ["value", "name"]
			}),
			value: this.builderType,
			displayField: "name",
			valueField: "value",
			triggerAction: "all",
			queryMode: "local",
			listeners: {
				select: function(combo, record) {
					this.changeBuilderType(record[0].get("value"));
					this.fireEvent("change", this);
				},
				scope: this
			},
			width: 60
		};
	},
	changeBuilderType: function(type) {
		if (type !== this.builderType) {
			this.builderType = type;
			var child = this.filter.filters[0];
			switch (type) {
				case TolomeoExt.Styler.FilterBuilder.ANY_OF:
					this.filter.type = OpenLayers.Filter.Logical.OR;
					child.type = OpenLayers.Filter.Logical.OR;
					break;
				case TolomeoExt.Styler.FilterBuilder.ALL_OF:
					this.filter.type = OpenLayers.Filter.Logical.OR;
					child.type = OpenLayers.Filter.Logical.AND;
					break;
				case TolomeoExt.Styler.FilterBuilder.NONE_OF:
					this.filter.type = OpenLayers.Filter.Logical.NOT;
					child.type = OpenLayers.Filter.Logical.OR;
					break;
				case TolomeoExt.Styler.FilterBuilder.NOT_ALL_OF:
					this.filter.type = OpenLayers.Filter.Logical.NOT;
					child.type = OpenLayers.Filter.Logical.AND;
					break;
			}
		}
	},
	createChildFiltersPanel: function() {
		this.childFilterContainer = new Ext.Container();
		var grandchildren = this.filter.filters[0].filters;
		var grandchild;
		for (var i = 0, len = grandchildren.length; i < len; ++i) {
			grandchild = grandchildren[i];
			var fieldCfg = {
				xtype: "styler_filterfield",
				columnWidth: 1,
				filter: grandchild,
				attributes: this.attributes,
				listeners: {
					change: function() {
						this.fireEvent("change", this);
					},
					scope: this
				}
			};
			var containerCfg = Ext.applyIf(grandchild instanceof OpenLayers.Filter.Logical ? {
				xtype: "styler_filterbuilder"
			} : {
				xtype: "container",
				layout: "form",
				hideLabels: true,
				items: fieldCfg
			}, fieldCfg);
			this.childFilterContainer.add(this.newRow(containerCfg));
		}
		return this.childFilterContainer;
	},
	newRow: function(filterContainer) {
		var ct = Ext.create("Ext.Container", {
			layout: "column",
			items: [{
				xtype: "container",
				width: 28,
				style: "padding-left: 2px",
				items: {
					xtype: "button",
					tooltip: "Rimuovi Condizione",
					iconCls: "delete",
					handler: function(btn) {
						this.removeCondition(ct, filterContainer.filter);
					},
					scope: this
				}
			}, filterContainer]
		});
		return ct;
	},
	getBuilderType: function() {
		var type = this.defaultBuilderType;
		if (this.filter) {
			var child = this.filter.filters[0];
			if (this.filter.type === OpenLayers.Filter.Logical.NOT) {
				switch (child.type) {
					case OpenLayers.Filter.Logical.OR:
						type = TolomeoExt.Styler.FilterBuilder.NONE_OF;
						break;
					case OpenLayers.Filter.Logical.AND:
						type = TolomeoExt.Styler.FilterBuilder.NOT_ALL_OF;
						break;
				}
			} else {
				switch (child.type) {
					case OpenLayers.Filter.Logical.OR:
						type = TolomeoExt.Styler.FilterBuilder.ANY_OF;
						break;
					case OpenLayers.Filter.Logical.AND:
						type = TolomeoExt.Styler.FilterBuilder.ALL_OF;
						break;
				}
			}
		}
		return type;
	}
});
Ext.namespace("TolomeoExt.Styler");

Ext.define("TolomeoExt.Styler.RulePanel", {
	extend: "Ext.TabPanel",
	alias: "widget.styler_rulepanel",
	fonts: undefined,
	symbolType: "Point",
	rule: null,
	attributes: null,
	nestedFilters: true,
	minScaleDenominatorLimit: Math.pow(0.5, 19) * 40075016.68 * 39.3701 * OpenLayers.DOTS_PER_INCH / 256,
	maxScaleDenominatorLimit: 40075016.68 * 39.3701 * OpenLayers.DOTS_PER_INCH / 256,
	scaleLevels: 20,
	scaleSliderTemplate: "{scaleType} Scale 1:{scale}",
	modifyScaleTipContext: Ext.emptyFn,
	
	initComponent: function() {
		
		this.addEvents('change');
	/*
		this.addEvents('save');
		this.addEvents('cancel');
		
		this.buttons = ["->", {
						text: "Annulla",
						iconCls: "cancel",
						handler: function() {
							this.fireEvent('cancel');
						},
						scope: this
					}, {
						text: "Salva",
						iconCls: "save",
						handler: function() {
							this.fireEvent('save', this.rule);
							//this.close();
							//this.ruleDialog.disable();
							//this.updateRule(rule, newRule);
							//this.ruleDialog.close();
			//				this.sldManager.saveSld(layer, function() {
			//					this.ruleDialog.close();
			//					this.repaint();
			//					this.saving = false;
			//				}, this);
						},
						scope: this
					}];
		
		*/
		var defConfig = {
			plain: true,
			border: false
		};
		Ext.applyIf(this, defConfig);
		if (!this.rule) {
			this.rule = new OpenLayers.Rule({
				name: this.uniqueRuleName()
			});
		} else {
			if (!this.initialConfig.symbolType) {
				this.symbolType = this.getSymbolTypeFromRule(this.rule) || this.symbolType;
			}
		}
		this.activeTab = 0;
		this.textSymbolizer = Ext.create("TolomeoExt.Styler.TextSymbolizer", {
			symbolizer: this.getTextSymbolizer(),
			attributes: this.attributes,
			fonts: this.fonts,
			listeners: {
				change: function(symbolizer) {
					this.fireEvent("change", this, this.rule);
				},
				scope: this
			}
		});
		this.scaleLimitPanel = Ext.create("TolomeoExt.Styler.ScaleLimitPanel", {
			maxScaleDenominator: this.rule.maxScaleDenominator || undefined,
			limitMaxScaleDenominator: !!this.rule.maxScaleDenominator,
			maxScaleDenominatorLimit: this.maxScaleDenominatorLimit,
			minScaleDenominator: this.rule.minScaleDenominator || undefined,
			limitMinScaleDenominator: !!this.rule.minScaleDenominator,
			minScaleDenominatorLimit: this.minScaleDenominatorLimit,
			scaleLevels: this.scaleLevels,
			scaleSliderTemplate: this.scaleSliderTemplate,
			modifyScaleTipContext: this.modifyScaleTipContext,
			listeners: {
				change: function(comp, min, max) {
					this.rule.minScaleDenominator = min;
					this.rule.maxScaleDenominator = max;
					this.fireEvent("change", this, this.rule);
				},
				scope: this
			}
		});
		this.filterBuilder = Ext.create("TolomeoExt.Styler.FilterBuilder", {
			allowGroups: this.nestedFilters,
			filter: this.rule && this.rule.filter && this.rule.filter.clone(),
			attributes: this.attributes,
			listeners: {
				change: function(builder) {
					var filter = builder.getFilter();
					this.rule.filter = filter;
					this.fireEvent("change", this, this.rule)
				},
				scope: this
			}
		});
		this.items = [{
			title: "Etichette",
			autoScroll: true,
			bodyStyle: {
				"padding": "10px"
			},
			items: [{
				xtype: "fieldset",
				title: "Caratteristiche Etichetta",
				autoHeight: true,
				checkboxToggle: true,
				collapsed: !this.hasTextSymbolizer(),
				items: [this.textSymbolizer],
				listeners: {
					collapse: function() {
						OpenLayers.Util.removeItem(this.rule.symbolizers, this.getTextSymbolizer());
						this.fireEvent("change", this, this.rule);
					},
					expand: function() {
						this.setTextSymbolizer(this.textSymbolizer.symbolizer);
						this.fireEvent("change", this, this.rule);
					},
					scope: this
				}
			}]
		}];
		if (this.getSymbolTypeFromRule(this.rule) || this.symbolType) {
			this.items = [{
				title: "Base",
				autoScroll: true,
				items: [
					this.createHeaderPanel(),
					this.createSymbolizerPanel()
				]
			}, this.items[0], {
				title: "Avanzato",
				defaults: {
					style: {
						margin: "7px"
					}
				},
				autoScroll: true,
				items: [{
					xtype: "fieldset",
					title: "Limite per Scala",
					checkboxToggle: true,
					collapsed: !(this.rule && (this.rule.minScaleDenominator || this.rule.maxScaleDenominator)),
					autoHeight: true,
					items: [this.scaleLimitPanel],
					listeners: {
						collapse: function() {
							delete this.rule.minScaleDenominator;
							delete this.rule.maxScaleDenominator;
							this.fireEvent("change", this, this.rule)
						},
						expand: function() {
							var tab = this.getActiveTab();
							this.activeTab = null;
							this.setActiveTab(tab);
							var changed = false;
							if (this.scaleLimitPanel.limitMinScaleDenominator) {
								this.rule.minScaleDenominator = this.scaleLimitPanel.minScaleDenominator;
								changed = true;
							}
							if (this.scaleLimitPanel.limitMaxScaleDenominator) {
								this.rule.maxScaleDenominator = this.scaleLimitPanel.maxScaleDenominator;
								changed = true;
							}
							if (changed) {
								this.fireEvent("change", this, this.rule)
							}
						},
						scope: this
					}
				}, {
					xtype: "fieldset",
					title: "Limite per Condizione",
					checkboxToggle: true,
					collapsed: !(this.rule && this.rule.filter),
					autoHeight: true,
					items: [this.filterBuilder],
					listeners: {
						collapse: function() {
							delete this.rule.filter;
							this.fireEvent("change", this, this.rule)
						},
						expand: function() {
							var changed = false;
							this.rule.filter = this.filterBuilder.getFilter();
							this.fireEvent("change", this, this.rule)
						},
						scope: this
					}
				}]
			}]
		}
		this.items[0].autoHeight = true;
		this.addEvents("change");
		this.on({
			tabchange: function(panel, tab) {
				tab.doLayout();
			},
			scope: this
		});
		TolomeoExt.Styler.RulePanel.superclass.initComponent.call(this);
	},
	
	hasTextSymbolizer: function() {
		var candidate, symbolizer;
		for (var i = 0, ii = this.rule.symbolizers.length; i < ii; ++i) {
			candidate = this.rule.symbolizers[i];
			if (candidate instanceof OpenLayers.Symbolizer.Text) {
				symbolizer = candidate;
				break;
			}
		}
		return symbolizer;
	},
	
	getTextSymbolizer: function() {
		var symbolizer = this.hasTextSymbolizer();
		if (!symbolizer) {
			symbolizer = new OpenLayers.Symbolizer.Text();
		}
		return symbolizer;
	},
	
	setTextSymbolizer: function(symbolizer) {
		var found;
		for (var i = 0, ii = this.rule.symbolizers.length; i < ii; ++i) {
			candidate = this.rule.symbolizers[i];
			if (this.rule.symbolizers[i] instanceof OpenLayers.Symbolizer.Text) {
				this.rule.symbolizers[i] = symbolizer;
				found = true;
				break;
			}
		}
		if (!found) {
			this.rule.symbolizers.push(symbolizer);
		}
	},
	
	uniqueRuleName: function() {
		return OpenLayers.Util.createUniqueID("rule_");
	},
	
	createHeaderPanel: function() {
		this.symbolizerSwatch = Ext.create("TolomeoExt.Styler.FeatureRenderer", {
			symbolType: this.symbolType,
			symbolizers: this.rule.symbolizers,
			fieldLabel: "Simbolo",
			labelAlign: "top"
		});
		return {
			xtype: "form",
			border: false,
			labelAlign: "top",
			defaults: {
				border: false
			},
			style: {
				"padding": "0.3em 0 0 1em"
			},
			items: [{
				layout: "column",
				defaults: {
					border: false,
					style: {
						"padding-right": "1em"
					}
				},
				items: [{
					layout: "form",
					width: 150,
					items: [{
						xtype: "textfield",
						fieldLabel: "Nome",
						labelAlign: "top",
						anchor: "95%",
						value: this.rule && (this.rule.title || this.rule.name || ""),
						listeners: {
							change: function(el, value) {
								this.rule.title = value;
								this.fireEvent("change", this, this.rule);
							},
							scope: this
						}
					}]
				}, {
					layout: "form",
					width: 70,
					items: [
						this.symbolizerSwatch
					]
				}]
			}]
		};
	},
	
	createSymbolizerPanel: function() {
		var candidate, symbolizer;
		var Type = OpenLayers.Symbolizer[this.symbolType];
		var existing = false;
		if (Type) {
			for (var i = 0, ii = this.rule.symbolizers.length; i < ii; ++i) {
				candidate = this.rule.symbolizers[i];
				if (candidate instanceof Type) {
					existing = true;
					symbolizer = candidate;
					break;
				}
			}
			if (!symbolizer) {
				symbolizer = Ext.create("Type", {
					fill: false,
					stroke: false
				});
			}
		} else {
			throw new Error("Appropriate symbolizer type not included in build: " + this.symbolType);
		}
		var cfg = {
			xtype: "styler_" + this.symbolType.toLowerCase() + "symbolizer",
			symbolizer: symbolizer,
			bodyStyle: {
				padding: "10px"
			},
			border: false,
			labelWidth: 70,
			defaults: {
				labelWidth: 70
			},
			listeners: {
				change: function(symbolizer) {
					this.symbolizerSwatch.setSymbolizers([symbolizer], {
						draw: this.symbolizerSwatch.rendered
					});
					if (!existing) {
						this.rule.symbolizers.push(symbolizer);
						existing = true;
					}
					this.fireEvent("change", this, this.rule);
				},
				scope: this
			}
		};
		if (this.symbolType === "Point" && this.pointGraphics) {
			cfg.pointGraphics = this.pointGraphics;
		}
		return cfg;
	},
	
	getSymbolTypeFromRule: function(rule) {
		var candidate, type;
		for (var i = 0, ii = rule.symbolizers.length; i < ii; ++i) {
			candidate = rule.symbolizers[i];
			if (!(candidate instanceof OpenLayers.Symbolizer.Text)) {
				type = candidate.CLASS_NAME.split(".").pop();
				break;
			}
		}
		return type;
	}
	
});
/* 
 Tolomeo is a developing framework for visualization, editing,  
 geoprocessing and decisional support application based on cartography.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 This file is part of Tolomeo.
 
 Tolomeo is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License 
 as published by the Free Software Foundation; either version 3 of the License, 
 or (at your option) any later version.
 
 Tolomeo is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License along with Tolomeo; 
 if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110­1301  USA
 
 Developers Information:
 
 Tolomeo is developed by Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it 
 
 
 Versione in Italiano LGPL
 
 Tolomeo è un framework per lo sviluppo di applicazioni per
 visualizzazione, editing, geoprocessing e supporto alla decisione basate su cartografia.
 
 Tolomeo Copyright 2011 Comune di Prato;
 
 Questo file fa parte di Tolomeo.
 
 Tolomeo è un software libero; è possibile redistribuirlo e / o 
 modificarlo sotto i termini della GNU Lesser General Public License, 
 come pubblicato dalla Free Software Foundation, sia la versione 3 della licenza o (a propria scelta) una versione successiva.
  
 Tolomeo è distribuito nella speranza che possa essere utile,
 ma SENZA ALCUNA GARANZIA, senza neppure la garanzia implicita di COMMERCIABILITÀ o
 IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU Lesser General Public License per ulteriori dettagli.
 
 Si dovrebbe avere ricevuto una copia della GNU Lesser General Public insieme a Tolomeo, in caso contrario, 
 si scriva alla Free Software  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110­1301 USA
   
 
 Informazioni Sviluppatori:
 
 Tolomeo è sviluppato dal Comune di Prato
 
 Alessandro Radaelli
 Federico Nieri
 Mattia Gennari
 
 sit@comune.prato.it
*/


/**
 * Class: TolomeoExt.ToloButtonPanelExt
 * 
 * Inherits from:
 *  - <Ext.Toolbar>
 *
 */

Ext.define('TolomeoExt.Styler.RuleGeneratorPanel', { 

	extend: 'Ext.Panel',

	fonts: undefined,
	symbolType : "Point",
	rule : null,
	attributes : null,
	nestedFilters : true,
	minScaleDenominatorLimit : Math.pow(0.5, 19) * 40075016.68 * 39.3701 * OpenLayers.DOTS_PER_INCH / 256,
	maxScaleDenominatorLimit : 40075016.68 * 39.3701 * OpenLayers.DOTS_PER_INCH / 256,
	scaleLevels : 20,
	scaleSliderTemplate : "{type} Scala 1:{scale}",
	modifyScaleTipContext : Ext.emptyFn,
	height : 300,
	width : 500,
		
	nomeCampoTematizzazione : "",
	numeroClassiTematizzazione : 2,
	precisioneDecimale : 0,
	tipoCreazione: null,
	
	statics: {
		TIPOGENERAZIONE : {
				SEMPLICE : {
					'nome': 'Semplice',
					'titoloFinestra': "Creazione nuova stilizzazione di tipo Semplice",
					'codice': 0},
				NATURAL_BREAK : {
					'nome': 'Natural Break',
					'titoloFinestra': "Creazione nuova stilizzazione di tipo Natural Break",
					'mostraPrecisioneDecimale': false,
					'mostraNumeroClassi': true,
					'codice': 1},
				EQUAL_COUNT : {
					'nome': 'Equal Count',
					'titoloFinestra': "Creazione nuova stilizzazione di tipo Equal Count",
					'mostraNumeroClassi': true,
					'mostraPrecisioneDecimale': true,
					'codice': 2},
				EQUAL_RANGE : {
					'nome': 'Equal Range',
					'titoloFinestra': "Creazione nuova stilizzazione di tipo Equal Range",
					'mostraNumeroClassi': true,
					'mostraPrecisioneDecimale': true,
					'codice': 3},
				VALORI_UNIVOCI : {
					'nome': 'Valori Univoci',
					'titoloFinestra': "Creazione nuova stilizzazione con Valori Univoci",
					'mostraNumeroClassi': false,
					'mostraPrecisioneDecimale': false,
					'codice': 4}
			}
	},
	
	initComponent : function() {		
		
		// Applico i default
		TolomeoExt.Vars.ApplyIfDefaults(this);

		var defConfig = {
			plain : true,
			border : false
		};		
		Ext.applyIf(this, defConfig);
		if (!this.rule) {
			this.rule = new OpenLayers.Rule({
				name : this.uniqueRuleName()
			});
		} else {
            if (!this.initialConfig.symbolType) {
                this.symbolType = this.getSymbolTypeFromRule(this.rule) || this.symbolType;
            }
        }		
		this.activeTab = 0;
		//TODO ALE
		/*this.textSymbolizer = new gxp.TextSymbolizer({
            symbolizer: this.getTextSymbolizer(),
            attributes: this.attributes,
            fonts: this.fonts,
            listeners: {
                change: function (symbolizer) {
                    this.fireEvent("change", this, this.rule);
                },
                scope: this
            }
        });		
		this.scaleLimitPanel = new gxp.ScaleLimitPanel({
            maxScaleDenominator: this.rule.maxScaleDenominator || undefined,
            limitMaxScaleDenominator: !! this.rule.maxScaleDenominator,
            maxScaleDenominatorLimit: this.maxScaleDenominatorLimit,
            minScaleDenominator: this.rule.minScaleDenominator || undefined,
            limitMinScaleDenominator: !! this.rule.minScaleDenominator,
            minScaleDenominatorLimit: this.minScaleDenominatorLimit,
            scaleLevels: this.scaleLevels,
            scaleSliderTemplate: this.scaleSliderTemplate,
            modifyScaleTipContext: this.modifyScaleTipContext,
            listeners: {
                change: function (comp, min, max) {
                    this.rule.minScaleDenominator = min;
                    this.rule.maxScaleDenominator = max;
                    this.fireEvent("change", this, this.rule);
                },
                scope: this
            }
        });        
        this.filterBuilder = new gxp.FilterBuilder({
            allowGroups: this.nestedFilters,
            filter: this.rule && this.rule.filter && this.rule.filter.clone(),
            attributes: this.attributes,
            listeners: {
                change: function (builder) {
                    var filter = builder.getFilter();
                    this.rule.filter = filter;
                    this.fireEvent("change", this, this.rule)
                },
                scope: this
            }
        });*/				
		this.items = [ {
			title : "Etichettatura",
			autoScroll : true,
			bodyStyle : {
				"padding" : "10px"
			},
			items : [ {
				xtype : "fieldset",
				title : "Etichettatura Geometrie",
				autoHeight : true,
				width : 385,  // Dimensione del box che contiene le informazioni sulle etichette
				checkboxToggle : true,
				collapsed : !this.hasTextSymbolizer(),
				items : [ this.textSymbolizer ],
				listeners : {
                    collapse: function () {
                        OpenLayers.Util.removeItem(this.rule.symbolizers, this.getTextSymbolizer());
                        this.fireEvent("change", this, this.rule);
                    },
                    expand: function () {
                        this.setTextSymbolizer(this.textSymbolizer.symbolizer);
                        this.fireEvent("change", this, this.rule);
                    },
					scope : this
				}
			}]
		}];
		this.items = [{
			title : "Configurazione",
			autoScroll : true,
			defaults : {
				style : { margin : "7px" }
			},
				items : [{										
					xtype : "fieldset",
					title : "Propriet&agrave; della tematizzazione",
					collapsed : false,
					autoHeight : true,
					items : [{
						xtype : "combo",
						fieldLabel : "Campo valori",
						store : this.attributes,
						queryMode: "local",
						editable : false,
						triggerAction : "all",
						allowBlank : false,
						displayField : "name",
						valueField : "name",
					    forceSelection: true,
					    width : 250,
					    listWidth : 300,
						value : "",
						listeners : {
							select : function(combo, records) { 
										this.nomeCampoTematizzazione = records[0].get("name"); 
									},
							scope : this
						}
					}, {
						xtype : "numberfield",
						name : "numero_classi",
						fieldLabel : "Numero Classi",
						value : 1,
						allowBlank: false,
				        decimalPrecision: 0,
				        allowDecimals: false,
				        minValue: 1,
				        hidden: !this.tipoCreazione.mostraNumeroClassi,
				        hideLabel : !this.tipoCreazione.mostraNumeroClassi,
						//width : 80,
						//labelWidth : 90,
						listeners : {
							change : function(field, value) { numeroClassiTematizzazione = value; },
							scope : this
						}												
					}, {
						xtype : "numberfield",
						name : "numero_precisione_decimale",
						fieldLabel : this.tipoCreazione.mostraPrecisioneDecimale ? "Precisione decimale" : "",
						value : 0,
						allowBlank: false,
						hideLabel : !this.tipoCreazione.mostraPrecisioneDecimale,
				        decimalPrecision: 0,
				        minValue: 0,
				        allowDecimals: false,
				       	hidden : !this.tipoCreazione.mostraPrecisioneDecimale,
						//width : 80,
						//labelWidth : 90,
						listeners : {
							change : function(field, value) { this.precisioneDecimale = value; },
							scope : this
						}												
					}]
				}]
			}, {
				title : "Aspetto",
				autoScroll : true,
				//this.createHeaderPanel()
				items : [this.createSymbolizerPanel() ]
			},
			//this.items[0],
			{
				title : "Scala",
				defaults : {
					style : { margin : "7px" }
				},
				autoScroll : true,
				items : [{
                xtype: "fieldset",
                title: "Limite di scala",
                checkboxToggle: true,
                collapsed: !(this.rule && (this.rule.minScaleDenominator || this.rule.maxScaleDenominator)),
                autoHeight: true,
                items: [this.scaleLimitPanel],
                listeners: {
                    collapse: function () {
                        delete this.rule.minScaleDenominator;
                        delete this.rule.maxScaleDenominator;
                        this.fireEvent("change", this, this.rule)
                    },
                    expand: function () {
                        var tab = this.getActiveTab();
                        this.activeTab = null;
                        this.setActiveTab(tab);
                        var changed = false;
                        if (this.scaleLimitPanel.limitMinScaleDenominator) {
                            this.rule.minScaleDenominator = this.scaleLimitPanel.minScaleDenominator;
                            changed = true;
                        }
                        if (this.scaleLimitPanel.limitMaxScaleDenominator) {
                            this.rule.maxScaleDenominator = this.scaleLimitPanel.maxScaleDenominator;
                            changed = true;
                        }
                        if (changed) { this.fireEvent("change", this, this.rule) }
                    },
                    scope: this
                }
            }]
		}]

		this.items[0].autoHeight = true;
		
		this.bbar = [
				"->",
				{
					text : "Annulla",
					iconCls : "cancel",
					handler : function() {
						this.fireEvent('cancelPressed');
					},
					scope : this
				}, {
					text : "Genera",
					iconCls : "save",
					scope : this,
					handler : function() {
						Ext.getBody().mask('Elaborazione in corso...');

						//this.rule = this.finestraGenerazioneStileDlg.items.items[0].rule.clone();
															
						new TolomeoExt.ToloCrossAjax().request({
							url: this.TOLOMEOServer + this.TOLOMEOContext + "/AjaxGeneraStiliServlet",
							method: 'POST',
							params: {
								//url: this.urlWFS,
								tipoCreazione: this.tipoCreazione.codice,
								precisione: this.precisioneDecimale,
								classi : this.numeroClassiTematizzazione,
								campo : this.nomeCampoTematizzazione,
								codTPN: this.layer.codTPN,
								// TODO
								//codice_comune: codiceComuneParamJsLocal,
								codice_comune: ""
							},
							failure : this.generaStiliFailure,
							success : this.generaStiliSuccess,
							scope : this
						});
					}
				} ];
		
		
		this.addEvents("change");
		this.on({
			tabchange : function(panel, tab) { tab.doLayout(); },
			scope : this
		});
		this.callParent();
	},
	
	uniqueRuleName : function() {
		return OpenLayers.Util.createUniqueID("rule_");
	},
	
	createHeaderPanel : function() {	
		return {
			xtype : "form",
			border : false,
			labelAlign : "top",
			defaults : { border : false },
			style : { "padding" : "0.3em 0 0 1em" },
			items : [{
				layout : "column",
				defaults : {
					border : false,
					style : { "padding-right" : "1em" }
				}
			}]
		};
	},
	
	createSymbolizerPanel: function () {
        var candidate, symbolizer;
        var Type = OpenLayers.Symbolizer[this.symbolType];
        var existing = false;
        if (Type) {
        	if (this.rule.symbolizers) {
        		for (var i = 0, ii = this.rule.symbolizers.length; i < ii; ++i) {
                    candidate = this.rule.symbolizers[i];
                    if (candidate instanceof Type) {
                        existing = true;
                        symbolizer = candidate;
                        break;
                    }
                }
        	}
            
            if (!symbolizer) {
                symbolizer = new Type({
                    fill: false,
                    stroke: false
                });
            }
        } else {
            throw new Error("Impossibile trovare un form di tematizzazione per il tipo di geometria: " + this.symbolType);
        }
        
        var cfg = {
        	xtype: 'styler_' + this.symbolType.toLowerCase() + 'symbolizer',
            //xtype: "gx_genera" + this.symbolType.toLowerCase() + "symbolizer",
            symbolizer: symbolizer,
            withColor: false, 
            bodyStyle: { padding: "10px" },
            border: false,
            labelWidth: 70,
            defaults: { labelWidth: 70 },
            listeners: {
                change: function (symbolizer) {
                    this.symbolizerSwatch.setSymbolizers([symbolizer], {
                        draw: this.symbolizerSwatch.rendered
                    });
                    if (!existing) {
                        this.rule.symbolizers.push(symbolizer);
                        existing = true;
                    }
                    this.fireEvent("change", this, this.rule);
                },
                scope: this
            }
        };
        if (this.symbolType === "Point" && this.pointGraphics) {
            cfg.pointGraphics = this.pointGraphics;
        }
        
        return cfg;
    },
	hasTextSymbolizer: function () {
        var candidate, symbolizer;
        if (this.rule.symbolizers) {
        	for (var i = 0, ii = this.rule.symbolizers.length; i < ii; ++i) {
                candidate = this.rule.symbolizers[i];
                if (candidate instanceof OpenLayers.Symbolizer.Text) {
                    symbolizer = candidate;
                    break;
                }
            }
            return symbolizer;
        } else {
        	return null;
        }
        
    },
    getTextSymbolizer: function () {
        var symbolizer = this.hasTextSymbolizer();
        if (!symbolizer) {
            symbolizer = new OpenLayers.Symbolizer.Text();
        }
        return symbolizer;
    },
    setTextSymbolizer: function (symbolizer) {
        var found;
        for (var i = 0, ii = this.rule.symbolizers.length; i < ii; ++i) {
            candidate = this.rule.symbolizers[i];
            if (this.rule.symbolizers[i] instanceof OpenLayers.Symbolizer.Text) {
                this.rule.symbolizers[i] = symbolizer;
                found = true;
                break;
            }
        }
        if (!found) {
            this.rule.symbolizers.push(symbolizer);
        }
    },
    uniqueRuleName: function () {
        return OpenLayers.Util.createUniqueID("rule_");
    },
    createHeaderPanel: function () {
        this.symbolizerSwatch = Ext.create('TolomeoExt.Styler.FeatureRenderer', {
            symbolType: this.symbolType,
            symbolizers: this.rule.symbolizers,
            isFormField: true,
            fieldLabel: "Anteprima"
        });
        return {
            xtype: "form",
            border: false,
            labelAlign: "top",
            defaults: {
                border: false
            },
            style: {
                "padding": "0.3em 0 0 1em"
            },
            items: [{
                layout: "column",
                defaults: {
                    border: false,
                    style: {
                        "padding-right": "1em"
                    }
                },
                items: [{
                    layout: "form",
                    width: 70,
                    items: [this.symbolizerSwatch]
                }]
            }]
        };
    },
    getSymbolTypeFromRule: function (rule) {
        var candidate, type;
        for (var i = 0, ii = rule.symbolizers.length; i < ii; ++i) {
            candidate = rule.symbolizers[i];
            if (!(candidate instanceof OpenLayers.Symbolizer.Text)) {
                type = candidate.CLASS_NAME.split(".").pop();
                break;
            }
        }
        return type;
    },
	
	generaStiliSuccess: function (results, store){
		
	/*
		var ajaxOptions = { method: 'post',
				url: this.TOLOMEOServer + this.TOLOMEOContext + '/AjaxSpatialQueryServlet',
				params: {
					dtInizioFiltro: this.temporalFilterDtInizio,
					dtFineFiltro: this.temporalFilterDtFine,
					coordX: point.x, 
					coordY: point.y,
					codTPN: codTPN,
					range: tolleranceRange,
					SRID: this.paramsJS.mappe.SRID,
					format: 'ext',
					selectionMode: selectionMode,
					//Parametri aggiunti per GetFeatureInfo
					bbox:  bounds.left+","+bounds.bottom+","+bounds.right+","+bounds.top ,
					mapwidth:  this.viewer.pluginGetMapWidth()  ,
					mapheight: this.viewer.pluginGetMapViewerHeight() ,
					X: mapXPixel,
					Y: mapYPixel,
					additionalWMSLayers: (additionalWMSLayers && additionalWMSLayers.length > 0) ? Ext.JSON.encode(additionalWMSLayers) : undefined,
					paramPreset: this.paramsJS.nomePreset
				},
				success: function(results, store){this.ajaxQuerySelectOK(results, store, addToSelected, visualize);},
				failure: function(transport){
					this.fireEvent('selectRequestEnd',{
						ok:false,
						nResults:0,
						errText:transport.responseText?transport.responseText:""+transport
					});
					this.showAjaxError(transport);
				}, 
				scope: this
			}
			
			// Aggiunta parametri WMS da url
			Ext.apply(ajaxOptions.params, this.paramsJS.urlAdditionalParams);
					
			if(this.fireEvent('selectRequestBeforeStart')){
				new TolomeoExt.ToloCrossAjax().request(ajaxOptions);
				this.fireEvent('selectRequestStart');
				*/
		
		var classiGenerate;
		if(Ext.isEmpty(response.responseText)) return;
		else classiGenerate = Ext.decode(response.responseText);

		var panel = this.getLegend();													
		// Rimuovo le regole presenti											
		while(panel.rules.length > 0)
		{
			for ( var h = 0; h < panel.rules.length; h++) {
				panel.rules.remove(panel.rules[h]);		
				this.fireEvent("ruleremoved", panel.rules[h]);
			}
		}
		
		this.saving = true;
		this.finestraGenerazioneStileDlg.disable();
		// INIZIO - Per ogni classe generata
		var classeCorrente = 0;
		var trovataAlmenoUnaClasse = false;
		
		while(classiGenerate[classeCorrente] != null && classiGenerate[classeCorrente] != undefined)
		{	
			var nuovaRegola = this.rule.clone();
			
			var masterFilter = new OpenLayers.Filter.Logical();
			masterFilter.type  = classiGenerate[classeCorrente].tipofiltro;
			
			for(filtroCorrente in classiGenerate[classeCorrente].filtri)
			{
				var emptyFilter = new OpenLayers.Filter.Comparison();
				
				if(!Ext.isEmpty(classiGenerate[classeCorrente].filtri[filtroCorrente].valoreFiltro) &&
				   !Ext.isEmpty(classiGenerate[classeCorrente].filtri[filtroCorrente].tipoFiltro))
				{
					emptyFilter.value = classiGenerate[classeCorrente].filtri[filtroCorrente].valoreFiltro;
					emptyFilter.type  = classiGenerate[classeCorrente].filtri[filtroCorrente].tipoFiltro;
					emptyFilter.property = classiGenerate[classeCorrente].filtri[filtroCorrente].colonna;
					masterFilter.filters[filtroCorrente] = emptyFilter;
				}
			}

			if(panel.symbolType == "Line")
			{
				nuovaRegola.symbolizers[0].strokeColor = classiGenerate[classeCorrente].colore;
			}
			else
			{
				nuovaRegola.symbolizers[0].fillColor = classiGenerate[classeCorrente].colore;
			}
			nuovaRegola.name = classiGenerate[classeCorrente].nome;
			nuovaRegola.title = classiGenerate[classeCorrente].nome;
			nuovaRegola.filter = masterFilter;
			nuovaRegola.id =  "OpenLayers.Rule_" + classeCorrente;
			panel.rules.push(nuovaRegola);
			trovataAlmenoUnaClasse = true;
			classeCorrente = classeCorrente + 1;
			this.fireEvent("ruleadded", nuovaRegola);
		}// FINE - Per ogni classe generata

		if(!trovataAlmenoUnaClasse)
		{
			Ext.MessageBox.show({
				title: 'Errore',
				msg: "Impossibile generare delle classi per con le impostazioni correnti",
				buttons: Ext.MessageBox.OK,
				icon: Ext.MessageBox.ERROR
			});
			Ext.getBody().unmask();
			return;
		}
		
		this.sldManager.saveSld(this.currentLayer, function(){
			this.repaint();
		}, this);
				
		this.saving = false;
		
		this.repaint();
		panel.update();
		
		//this.currentLayer.display(false);
		//this.currentLayer.clearGrid();
		//this.currentLayer.mergeNewParams({'random':Math.random()});
		//this.currentLayer.redraw(true);
		//this.currentLayer.display(true);
		
		if(this.finestraGenerazioneStileDlg)
		{
			this.finestraGenerazioneStileDlg.close();
			this.finestraGenerazioneStileDlg.destroy();
		}
		
		
	},
	
	generaStiliFailure: function (){
		Ext.MessageBox.show({
			title: 'Errore',
			msg: "Errore nella generazione della stilizzazione",
			buttons: Ext.MessageBox.OK,
			icon: Ext.MessageBox.ERROR
		});
	}
});

/**
 * Plugin per la gestione di richieste e operazioni 
 * che coinvolgono la form codeless.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.ToloCodelessManager', {
	
	extend: 'Ext.util.Observable',
	
	id: "cl_manager",
	
	/**
	 * @cfg {String} TOLOMEOServer
	 * URL di base del contesto di Tolomeo.
	 */
	TOLOMEOServer: null,
	
	/**
	 * @cfg {String} TOLOMEOContext
	 * Contesto di Tolomeo.
	 */
	TOLOMEOContext: null,
	
	/**
	 * @property {TolomeoExt.ToloMapAPIExt} mapApiExt
	 * Oggetto di controllo della mappa.
	 */
	
	/**
	 * @cfg {Ext.data.Store} store
	 * Store dei dati su cui agisce il manager.
	 */
	
	/**
	 * @property {String} updateDialogTitle
	 * Titolo da mostrare per la dialog di aggiornemnto dati.
	 */
    updateDialogTitle: "Aggiornamento",
    
	/**
	 * @property {String} updateDialogText
	 * Testo da mostrare all'interno della dialog di aggiornemnto dati.
	 */
    updateDialogText: "Non sono presenti dati da aggiornare",
    
	/**
	 * @property {String} deleteDialogTitle
	 * Titolo da mostrare per la dialog di cancellazione dati.
	 */
    deleteDialogTitle: "Cancellazione",
    
	/**
	 * @property {String} deleteDialogText
	 * Testo da mostrare all'interno della dialog di cancellazione dati.
	 */
    deleteDialogText: "Procedere con la cancellazione dei dati?",

	/**
     * Crea un nuovo TolomeoExt.ToloCodelessManager.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	constructor: function(config) {
		this.callParent(arguments);
		
		Ext.apply(this, config);
		
		this.addEvents(
	        /**
			 * @event
			 * Lanciato alla fallimento della richiesta.
			 */
			"loaddatafailure",
	        /**
			 * @event
			 * Lanciato prima di effettuare la richiesta di aggiornamento dati.
			 */
			"beforeupdatedata",
	        /**
			 * @event
			 * Lanciato prima di effettuare la richiesta di caricamento dati.
			 */
			"beforeloaddata",
	        /**
			 * @event
			 * Lanciato al termine della richiesta di caricamento se questa è andata a buon fine.
			 */
			"loaddata",
	        /**
			 * @event
			 * Lanciato al termine della richiesta di aggiornamento se questa è andata a buon fine.
			 */
			"updatedata",
	        /**
			 * @event
			 * Lanciato prima di effettuare la richiesta di cancellazione dei dati.
			 */
			"beforedeletedata",
	        /**
			 * @event
			 * Lanciato al termine della richiesta di cancellazione se questa è andata a buon fine.
			 */
			"deletedata",
	        /**
			 * @event
			 * Lanciato prima di effettuare la richiesta di creazione di una feature.
			 */
			"beforecreatedata",
	        /**
			 * @event
			 * Lanciato al termine della richiesta di creazione di una nuova feature se questa è andata a buon fine.
			 */
			"createdata",
	        /**
			 * @event
			 * Lanciato a seguito della selezione di una feature in mappa.
			 */
			"objectselected",
	        /**
			 * @event
			 * Lanciato a seguito del cambio di modalità di funzionamento (edit, view o new)
			 */
			"changemode",
	        /**
			 * @event
			 * Lanciato a seguito del ripristino dello store ai valori iniziali
			 */
			"restore"
		);	
	},
	
	/**
     * Imposta l'oggetto di controllo della mappa per intercettare le 
     * operazioni utente (eventi tolomeo) e procedere con la gestione della form.
     * @param {TolomeoExt.ToloMapAPIExt} mapApiExt oggetto di controllo della mappa.
     */
	setMapApiExt: function(mapApiExt){
		this.mapApiExt = mapApiExt;
		this.mapApiExt.on({
			codelessaction: function(eventoLayer, tipoEvento, object){
				this.selection = object;
				
				switch(tipoEvento){
					case 0: // Identify
						// /////////////////////////////////////////////
						// Caricamento di tutte le informazioni al 
						// fine di preparare la griglia per la modalità
						// di visualizzazione
						// /////////////////////////////////////////////
						var fparams = {
							codTPN: this.selection.codTPN,
							command: "view",
							IDTPN: this.selection.key
						}; 
						
						this.loadViewMode(fparams);
						break;
					case 1: // Delete
			    		Ext.MessageBox.confirm(
		    				this.deleteDialogTitle, 
		    				this.deleteDialogText, 
		    				function(btn){
			    			   if(btn === 'yes'){
									// ///////////////////////////////////////
									// Cancella l'oggetto selezionato
									// ///////////////////////////////////////
									var fparams = {
										codTPN: this.selection.codTPN,
										command: "delete",
										IDTPN: this.selection.key
									}; 
									
									this.cancel(fparams);
			    			   }
		    				}, 
		    				this
						);
						break;
					case 3: // Edit
						// /////////////////////////////////////////////
						// Caricamento di tutte le informazioni al 
						// fine di preparare la griglia per la modalità 
						// di modifica
						// /////////////////////////////////////////////
						var fparams = {
							codTPN: this.selection.codTPN,
							command: "edit",
							IDTPN: this.selection.key
						}; 
						
						this.loadEditMode(fparams);
						break;
					case 4: // New
						// ////////////////////////////////////////////
						// Caricamento di tutte le informazioni al 
						// fine di preparare la griglia per l'aggiunta 
						// di un nuovo elemento 
						// ////////////////////////////////////////////
						if(!this.selection){
							this.selection = this.mapApiExt.geoCoordField.getValue();
							this.selection = Ext.decode(this.selection);
						}
						
						var fparams = {
							codTPN: this.selection.codTPN,
							command: "edit"
						}; 
						
						this.loadEditMode(fparams, true);
						break;
				}
			},	
			onObjectSelect: function(){
				this.fireEvent("objectselected");
			},
			scope: this
		});
	},
	
	/**
     * Imposta la modalità  di funzionamento del manager.
     * @param {String} mode Modalità  di configurazione (view, edit, new).
     * @param {Ext.Data.Store} store Store da usare per componenti di tipo UI
     */
	setMode: function(mode, store){
		this.store = store;
		this.fireEvent("changemode", mode, store);
	},
	
	/**
     * Handler invocato in caso di fallimento della richiesta Ajax.
     * @param {Ext.Data.Store} store Oggetto rappresentante lo store dei dati. 
     *
     */
	doAjaxFailure: function (store) {
		this.fireEvent("loaddatafailure", store);
    },
    
    /**
     * Metodo di caricamento dello store delle features per la modalità 'view'.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    loadViewMode: function(fparams){       	
    	this.fireEvent("beforeloaddata");
    	
		this.request(
			fparams,
			"GET",
    		function(results, store){
				this.setMode("view", store);
    			this.fireEvent("loaddata", store);
    		},
    		this.doAjaxFailure,
    		this
		);
    },
    
    /**
     * Metodo di caricamento dello store delle features per la modalità 'edit'.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    loadEditMode: function(fparams, isNew){       	
    	this.fireEvent("beforeloaddata");
    	
		this.request(
			fparams,
			"GET",
    		function(results, store){
				var mode = "edit";
				// //////////////////////////////////////////////////////////////
				// Controlla se stiamo cercando di creare un nuovo elemento o no 
				// //////////////////////////////////////////////////////////////
				if(isNew){
					mode = "new";
				}
				
				this.setMode(mode, store);
    			this.fireEvent("loaddata", store);
    		},
    		this.doAjaxFailure,
    		this
		);
    },
    
    /**
     * Metodo di aggiornamento dei dati.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    update: function(fparams){
    	this.fireEvent("beforeupdatedata");
    	
    	var updatedRecords = this.store.getUpdatedRecords();
    	
    	if(updatedRecords.length > 0){
    		var params = Ext.applyIf(
				{
					codTPN: this.selection.codTPN,
					command: "update",
					IDTPN: this.selection.key
				}, 
				fparams
			); 
    		
    		var data = "[";
    		for(var i=0; i<updatedRecords.length; i++){
    			var record = updatedRecords[i];
    			var values = record.data;
    			data += Ext.encode(values);
    			
    			if(i+1 != updatedRecords.length){
    				data += ",";
    			}
    		}
    		data += "]";
    		
    		params.data = data;
    		
    		this.request(
				params,
				"POST",
				function(results, store){
					// /////////////////////////////////////////////////
					// Ridisegna il layer per aggiornare lo stato di 
					// eventiali etichette che sono state modificate 
					// durante la procedura di aggiornamento.
					// /////////////////////////////////////////////////
					this.mapApiExt.viewer.pluginRefreshMap();
					
					this.setMode("edit", store);
	    			this.fireEvent("updatedata", store);
	    		},
	    		this.doAjaxFailure,
	    		this
    		);
    	}else{
            Ext.Msg.show({
                title: this.updateDialogTitle,
                msg: this.updateDialogText,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.INFO
            }); 
    	}
    },
    
    /**
     * Metodo di cancellazione dei dati.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    cancel: function(fparams){
    	this.fireEvent("beforedeletedata");
    	
		this.request(
			fparams,
			"POST",
    		function(results){
				if(results){
					// /////////////////////////////////////////////////
					// Ridisegna il layer per aggiornare lo stato di 
					// eventiali etichette che sono state modificate 
					// durante la procedura di aggiornamento.
					// /////////////////////////////////////////////////
					this.mapApiExt.viewer.pluginRefreshMap();
					
					this.fireEvent("deletedata", results);
					
					// ////////////////////////////////////
					// Informa l'utente che l'operazione è 
					// stata completata con successo.
					// ////////////////////////////////////
		            Ext.Msg.show({
		                title: this.deleteDialogTitle,
		                msg: results[0].data.Descrizione,
		                buttons: Ext.Msg.OK,
		                icon: Ext.MessageBox.INFO
		            }); 
				}			
    		},
    		this.doAjaxFailure,
    		this
		);
    },
    
    /**
     * Metodo per la raccolta dati al fine di creare un nuovo elemento.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    create: function(fparams){
    	this.fireEvent("beforecreatedata");
    	var updatedRecords = this.store.getUpdatedRecords();
    	
    	if(updatedRecords.length > 0){
    		var params = Ext.applyIf(
				{
					codTPN: this.selection.codTPN,
					command: "new",
					SRID: this.selection.SRID,
					geometry: this.selection.geometry
				}, 
				fparams
			); 
    		
    		var data = "[";
    		for(var i=0; i<updatedRecords.length; i++){
    			var record = updatedRecords[i];
    			var values = record.data;
    			data += Ext.encode(values);
    			
    			if(i+1 != updatedRecords.length){
    				data += ",";
    			}
    		}
    		data += "]";
    		
    		params.data = data;
    		
    		this.request(
				params,
				"POST",
				function(results, store){
					// /////////////////////////////////////////////////
					// Ridisegna il layer per aggiornare lo stato di 
					// eventiali etichette che sono state modificate 
					// durante la procedura di aggiornamento.
					// /////////////////////////////////////////////////
					this.mapApiExt.viewer.pluginRefreshMap();
					
					this.setMode("edit", store);
	    			this.fireEvent("createdata", store);
	    		},
	    		this.doAjaxFailure,
	    		this
    		);
    	}else{
            Ext.Msg.show({
                title: this.updateDialogTitle,
                msg: this.updateDialogText,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.INFO
            }); 
    	}
    },
    
    /**
     * Metodo di gestione della richiesta Ajax.
     */    
    request: function(params, method, success, failure, scope){
    	var submitOpt = {
    		url: this.TOLOMEOServer + this.TOLOMEOContext + '/LayerItemServlet',
    		method: method,
    		params: params,
    		success: success,
    		failure: failure ? failure : this.doAjaxFailure,
    		scope: scope
    	};
    	
		new TolomeoExt.ToloCrossAjax().request(submitOpt);
    },
    
    /**
     * Restituisce i metadati della richiesta.
     */  
    getRequestMetadata: function(store){
    	var gridStore = store || this.store;
		var proxy = gridStore.getProxy();
		var reader = proxy.getReader();
		var metadata = reader.metaData;
		
		return metadata;
    },
    
    /**
     * Ripristina i dati nello store eliminando le modifiche.
     *
     */
    restore: function(){
    	this.store.rejectChanges();
    	this.fireEvent("restore");
    }
	
});
/**
 * Strumento di visualizzazione ed editing dei dati configurabile, 
 * senza la necessità di scrivere codice (“codeless”) per Tolomeo. 
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.ToloCodeLessPanel', {

	extend: 'Ext.Panel',

	/**
	 * @cfg {Object} paramsJS
	 * Configurazioni specifiche del file di preset.
	 */
	paramsJS: null,

	/**
	 * @cfg {String} TOLOMEOServer
	 * URL di base del contesto di Tolomeo.
	 */
	TOLOMEOServer: null,

	/**
	 * @cfg {String} TOLOMEOContext
	 * Contesto di Tolomeo.
	 */
	TOLOMEOContext: null,
	
	/**
	 * @cfg {String} viewFieldSetTitle
	 * Testo del field set in modalità  di visualizzazione.
	 */
	viewFieldSetTitle: null, //"Visualizzazione Dati",
	
	/**
	 * @cfg {String} editFieldSetTitle
	 * Testo del field set in modalità  di modifica.
	 */
	editFieldSetTitle: "Modifica Dati",
	
	/**
	 * @cfg {String} newFieldSetTitle
	 * Testo del field set in modalità  di nuovo elemento.
	 */
	newFieldSetTitle: "Nuovo Elemento",
	
	/**
	 * @cfg {String} applyModsTooltip
	 * Testo da mostrare per il tootlip del pulsante di salvataggio delle modifiche.
	 */
	applyModsTooltip: "Applica Modifiche",
	
	/**
	 * @cfg {String} resetTooltip
	 * Testo da mostrare per il tootlip del pulsante di reset delle modifiche.
	 */
	resetTooltip: "Reimposta Campi",
	
	/**
	 * @cfg {String} restoreBoxTitle
	 * Titolo da mostrare per la dialog di conferma per il reset delle modiche.
	 */
	restoreBoxTitle: "Ripristino", 
	
	/**
	 * @cfg {String} restoreBoxText
	 * Testo da mostrare per la dialog di conferma per il reset delle modiche.
	 */
	restoreBoxText: "Procedere con il ripristino dei dati allo stato iniziale?", 

	/**
	 * @cfg {String} saveBoxTitle
	 * Titolo da mostrare per la dialog di conferma per il salvataggio delle modiche.
	 */
	saveBoxTitle: "Salvataggio", 
	
	/**
	 * @cfg {String} saveBoxText
	 * Testo da mostrare per la dialog di conferma per il salvataggio delle modiche.
	 */
	saveBoxText: "Procedere con il salvataggio?", 
	
	/**
	 * @cfg {String} missingIDTPNTitle
	 * Titolo da mostrare in fase di salvataggio se il campo relativo all'IDTPN non risulta valorizzato.
	 */
	missingIDTPNTitle: "IDTPN Mancante",
	
	/**
	 * @cfg {String} missingIDTPNText
	 * Testo da mostrare per la dialog di avviso in fase di salvataggio se il campo relativo all'IDTPN non risulta valorizzato.
	 */
	missingIDTPNText: "Il campo relativo all'IDTPN deve essere inserito prima di procedere",
	
	/**
     * @cfg {Object} autoCompleteCfg [autoCompleteCfg="{}"]
	 * Stabilisce la configurazione da usare per la funzionalità di autocompletamento.
	 *
	 * @example
	 * autoCompleteCfg: {
	 *  	url: 'http://localhost:8080/tolomeobinj/UniqueValueServlet',
	 *		pageSize: 10
	 * }
     */
    autoCompleteCfg: {},
    
	/**
	 * @cfg {Number} pageSize
	 * Indica il massimo numero di elementi per pagina per la combo di autocompletamento usato per 
	 * gli editor di FKs.
	 */
    pageSize: 10,
    
	/**
	 * @cfg {String} dateFormat [dateFormat="c"]
	 * Indica il formato per i campi editor di tipo "data" (il valore predefinito e 'c' che corrispondea 'ISO 8601 date').
	 */
    dateFormat: "c",
    
	/**
	 * @cfg {Array} dateFormats
	 * Formati di data ExtJS disponibili per gli editor di campi data di questo componente.
	 */
    dateFormats: [
        {java: "yyyy-MM-dd'T'HH:mm:ss", ext: "Y-m-d H:i:s"},
        {java: "yyyy-MM-dd", ext: "Y-m-d"},
        {java: "dd-MM-yyyy", ext: "d-m-Y"},
        {java: "dd-MM-yyyy", ext: "d-m-Y"},
        {java: "MM-dd-yyyy", ext: "m-d-Y"}		
    ],
    
	/**
	 * @property {TolomeoExt.ToloCodelessManager} codelessManager
	 * Gestore delle operazioni del componente.
	 */
	
	/**
	 * @property {Ext.grid.Panel} propertyGrid
	 * Griglia ExtJs per la presentazione e la modifica dei dati richiesti.
	 */
	
	/**
	 * @property {Ext.grid.Panel} decodeGrid
	 * Griglia ExtJs per la presentazione e la modifica dei dati relativi alle tabelle di decodifica.
	 */
	
	/**
	 * @property {String} mode
	 * Stringa che indica la modalità di funzionamento corrente della form.
	 */

	/**
     * Inizializza un nuovo TolomeoExt.ToloCodeLessPanel.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	initComponent: function(config){
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		// ///////////////////// //
		// FEATURE DI SELEZIONE  //
		// ///////////////////// //
		
		var gridStore = Ext.create('Ext.data.Store', {
		    fields: ["name", "nl", "type", "editable", "validation", "value", "format"],
		    proxy: {
		        type: 'memory',
		        reader: {
		            type: 'json',
		            root: 'rows'
		        }
		    }
		});
		
	    var cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
	    	clicksToEdit : 1,
	        autoCancel: false
	    });
	    
	    var me = this;
		this.propertyGrid = Ext.create('Ext.grid.Panel', {
			margin: "5 0 5 0",
			hideHeaders: true,
			store: gridStore,
		    columns: [
              {
            	  header: 'Nome',  
            	  dataIndex: 'name',
            	  tdCls: 'codelessnomecampo'
        //    	  flex: 50/100
              },              {
            	  header: 'NL',  
            	  dataIndex: 'nl',
                  hidden: true
              },
              {
            	  header: 'Tipo',  
            	  dataIndex: 'type',
                  hidden: true
              },
              {
            	  header: 'Editabile',  
            	  dataIndex: 'editable',
                  hidden: true
              },
              {
            	  header: 'Validation',  
            	  dataIndex: 'validation',
                  hidden: true
              }, 
              {
            	  header: 'Valore', 
            	  dataIndex: 'value',
            	  tdCls: 'codelessvalore',
            	  //flex: 50/100,
            	  renderer: function(value, metaData, record, rowIndex, store, view){
            		  var type = record.get("type"); 
	  	              switch (type) {
	                    case "java.util.Date":
	                    case "java.util.Calendar":
	                    	var format =  me.getDateFormat();
	                    	var date = Ext.util.Format.date(value, format);
	                    	return date;
	                        break;
	                    default:
	                    	var v;
	                    	if(value.value || value.value == ""){
	                    		// /////////////////////////////////////////
	                    		// Questo imposta il valore della combo di 
	                    		// autocompletamento (usato per le FK)
	                    		// /////////////////////////////////////////
	                    		v = value.value;
	                    	}else{
	                    		v = value;
	                    	}
	                		return v;
	  	              }
            	  },
            	  getEditor: function(record) {
            		  	var editable = record.get("editable");
            		  	if(editable){
                		    var type = record.get("type");
                		    
                		    // ///////////////////////////////////////////////////////
                		    // Imposta la regola di validazione usando la Regular 
                		    // Expression se esiste.
                		    // ///////////////////////////////////////////////////////
                		    var validation = record.get("validation");
                		    var baseConfig = {};
                		    if(validation != "undefined"){
                		    	var valueTest = new RegExp(validation);
                		    	baseConfig = {
    	                            validator: function(value) {
    	                                return valueTest.test(value) ? true : "Valore campo non valido";
    	                            }
    	                		}
                		    }
                		    
    	  	                switch (type) {
    		                    case "java.util.Date":
    		                		var format =  me.getDateFormat();
    		                		var config = Ext.apply({
		            		            allowBlank: false,
		            		            format: format
		            		        }, baseConfig);
    		                		
    		            		    return Ext.create('Ext.grid.CellEditor', { 
    		            		        field: Ext.create('Ext.form.field.Date', config)
    		            		    });
    		                        break;
    		                    case "java.lang.Boolean":
    		                		var config = Ext.apply({
		            		            allowBlank: false
		            		        }, baseConfig);
    		                		
    		            		    return Ext.create('Ext.grid.CellEditor', { 
    		            		        field: Ext.create('Ext.form.field.Checkbox', config)
    		            		    });
    		                        break;
    		                    case "net.sf.json.JSONObject":
    		                    	var value = record.get("value");
    		                    	if(value.codTPN){
    		                            var uniqueValuesStore = new TolomeoExt.data.ToloUniqueValuesStore({
    		                                pageSize: me.autoCompleteCfg.pageSize || me.pageSize,
    		                    			TOLOMEOServer: me.TOLOMEOServer,
    		                    			TOLOMEOContext: me.TOLOMEOContext
    		                            });
    		                            
    		                            me.initUniqueValuesStore(uniqueValuesStore, value.codTPN, value.property);
    		                            
        		                		var config = {
    		                                queryMode: "remote",
    		                                store: uniqueValuesStore,
    		                                pageSize: me.autoCompleteCfg.pageSize || me.pageSize,
    		                                typeAhead: false,
    		                                forceSelection: false,
    		                                remoteSort: true,
    		                                triggerAction: "all",
    		                                allowBlank: false,
    		                                displayField: "value",
    		                                valueField: "value",
    		                                minChars: 1,
       		                                matchFieldWidth: true,
       		                                listConfig:{
       		                                	minWidth: 100,
       		                                	width: 200
       		                                },
		       		                        listeners: {
	       		                              beforequery: function(evt) {
	       		                                  evt.combo.store.baseParams.start = 0;
	       		                                  evt.combo.store.baseParams.query = evt.combo.getValue();
	       		                              },
	       		                              scope: me
		       		                        }
    		                            };
        		                		
        		            		    return Ext.create('Ext.grid.CellEditor', { 
        		            		        field: Ext.create('TolomeoExt.widgets.form.ToloUniqueValuesCombo', config)
        		            		    });
        		            		    
        		            		    break;
    		                    	}
    		                    case "java.lang.String":
    		                		var config = Ext.apply({
		            		            allowBlank: false
		            		        }, baseConfig);
    		                		
    		            		    return Ext.create('Ext.grid.CellEditor', { 
    		            		        field: Ext.create('Ext.form.field.Text', config)
    		            		    });
    		                        break;
    		                    default:
    		                		var config = Ext.apply({
		            		            allowBlank: false
		            		        }, baseConfig);
    		                    
    		            		    return Ext.create('Ext.grid.CellEditor', { 
    		            		        field: Ext.create('Ext.form.field.Number', config)
    		            		    });
    		                }
            		  	}
            	  }
              }
            ],
            plugins: [cellEditing],
			listeners: {
				scope: this,
				edit: function(grid, cell){
					this.setBtnStatus(true);
				},
				beforeEdit: function(editor, context, eOpts){
            		// /////////////////////////////////////////
            		// Questo imposta il valore della combo di 
            		// autocompletamento (usato per le FK)
            		// /////////////////////////////////////////
					var value = editor.context.value;
					if(value.value || value.value == ""){
						editor.context.value = value.value;
					}
				}
			},
			// Autosize delle colonne
			viewConfig: {
		        listeners: {
		            refresh: function(dataview) {
		            	setTimeout(function(){ 
		            		dataview.panel.columns[0].autoSize(); 
		            		}, 1000);
		            	
		                /*Ext.each(dataview.panel.columns, function(column) {
		                    if (column.autoSizeColumn === true)
		                        column.autoSize();
		                })*/
		            	
		            }
		        }
		    }
		
		});
		
		
		this.fieldSet = Ext.create('Ext.form.FieldSet', {
			title: "",
			border: 0,
			anchor: "-1",
			//autoWidth: true,
			//autoHeight: true,
			hidden: true,
			items:[this.propertyGrid]
		});
		
		// ///////////////////// //
		// FORM DI PRESENTAZIONE //
		// ///////////////////// //
		
		this.formPanel = Ext.create('Ext.form.Panel', {
		    border: 0,	
		    cls: "tolomeo-formcodelessbbar",
		    layout: 'anchor',
		    hidden: true,
		    defaults: {
		        anchor: '100%'
		    },
		    items: [
		        this.fieldSet
		    ],
		    buttons: [{
		    	xtype: "button", 
		    	minWidth: '20',
		    	ref: "linkButton",
		    	text: "Il mio testo",
		    	href: "http://mappe.regione.toscana.it",
		    	hrefTarget: "_blank",
		    	disabled: false,
		    	hidden: true,
		    	scope: this
		    },{ 
		    	xtype: 'tbfill'
		    },{
		    	xtype: "button", 
		    	minWidth: '20',
		    	ref: "resetButton",
		    	tooltip: this.resetTooltip,
		    	iconCls: "reset",
		    	disabled: true,
		    	hidden: true,
		    	scope: this,
		    	handler: function(button){
		    		Ext.MessageBox.confirm(
	    				this.restoreBoxTitle,
	    				this.restoreBoxText,
	    				function(btn){
		    			   if(btn === 'yes'){
		    				   this.codelessManager.restore();
		    			   }
	    				}, 
	    				this
    				);
		    	}
		    },{
		    	xtype: "button", 
		    	minWidth: '20',
		    	ref: "saveButton",
		    	tooltip: this.applyModsTooltip,
		    	iconCls: "save",
		    	disabled: true,
		    	hidden: true,
		    	scope: this,
		    	handler: function(button){
		    		
		    		// ////////////////////////////////////////////////
		    		// La Griglia ExtJS esegue già il controllo di 
		    		// validità di un campo ripristinando il valore 
		    		// precedente nel caso in cui tale valore inserito 
		    		// sia invalido.
		    		// ////////////////////////////////////////////////
		    		
		    		Ext.MessageBox.confirm(
	    				this.saveBoxTitle,
	    				this.saveBoxText, 
	    				function(btn){
		    			   if(btn === 'yes'){
		    				   if(this.mode == "new"){
		    					   var record = this.propertyGrid.getStore().findRecord("nl", "NL_IDTPN");
		    					   var recordValue = record.get("value");
		    					   var editable = record.get("editable");
		    					   
		    					   // //////////////////////////////////////////////////////////
		    					   // Si controlla se il campo relativo all'IDTPN è valorizzato 
		    					   // nel caso in cui debba esserlo secondo le impostazioni del 
		    					   // server.
		    					   // //////////////////////////////////////////////////////////
		    					   if((!recordValue || recordValue == "") && editable){
		    				            Ext.Msg.show({
		    				                title: this.missingIDTPNTitle,
		    				                msg: this.missingIDTPNText,
		    				                buttons: Ext.Msg.OK,
		    				                icon: Ext.MessageBox.WARNING
		    				            }); 
		    					   }else{
		    						   this.codelessManager.create();
		    					   }
		    				   }else{
		    					   this.codelessManager.update();
		    				   }
		    			   }
	    				}, 
	    				this
    				);
		    	}
		    }]
		});
		
		this.callParent();
		this.buildManager(gridStore);
		this.codelessManager.on("loaddata", this.dataLoaded, this);
		
		this.add([this.formPanel]);
	},
	
	dataLoaded: function()
	{
		
		var linkButton = this.formPanel.query("button[ref=linkButton]")[0];
		var metadata = this.codelessManager.getRequestMetadata();
		
		if (metadata.layerURL != null && metadata.layerURL != "") {
			linkButton.setText(metadata.layerURLLabel);
			linkButton.setHref(metadata.layerURL);
			linkButton.show();
		} else {
			linkButton.hide();
		}
	},
	
	/**
     * Restituisce il formato data da usare per l'editor. 
     * 
     */
	getDateFormat: function(){
		var metadata = this.codelessManager.getRequestMetadata();
    	
		// ////////////////////////////////////////////////////////////
		// Usa ISO-8601 come formato data se non viene trovata nessuna 
		// corrispondenza attraverso l'invocazione di getExtDateFormat.
		// ////////////////////////////////////////////////////////////
		var format =  metadata ? (this.getExtDateFormat(metadata.dateFormat) || this.dateFormat) : this.dateFormat;
		return format;
	},
	
	/**
     * Converte il formato Data fornito dal server sulla base di quelli disponibili 
     * in configurazione. 
     * @param {String} format formato da usare per il campo editor della data.
     * 
     */
	getExtDateFormat: function(format){
		var date_format;
		
		if(format){
			for(var i=0; i<this.dateFormats.length; i++){
				var df = this.dateFormats[i];
				if(format == df.java){
					date_format = df.ext;
					break;
				}
			}
		}
		
		return date_format;
	},
	
	/**
     * Crea il componente Ext destinato a contenere il valore delle proprietà .
     * @param {TolomeoExt.data.ToloUniqueValuesStore} store Store della combo box di auto completamento.
     * @param {String} url Url del servizio remoto di auto completamento.
     * @param {String} layerName codTPN da usare com eparametro della richiesta.
     * @param {String} fieldName Nome della proprietà di cui ritornare i suggerimenti.
     * 
     */
    initUniqueValuesStore: function(store, layerName, fieldName) {
        var params = {
            inputs: {
            	featureTypeName: layerName,
                fieldName: fieldName
            },
            start: 0,
            limit: this.autoCompleteCfg.pageSize || this.pageSize
        };
        
        store.setParams(params);
    },
	
	/**
     * Crea il Gestore delle richieste se assente e registra gli eventi necessari.
     * @param {Ext.Data.Store} store Store che il Manager deve gestire.
     */
	buildManager: function(store){
		this.codelessManager = Ext.create('TolomeoExt.ToloCodelessManager', {
			TOLOMEOServer : this.TOLOMEOServer,
			TOLOMEOContext: this.TOLOMEOContext,
			store: store
		});
		
		this.codelessManager.on({
			changemode: function(mode, store){
				this.setFormMode(mode, store);
			},
			objectselected: function(){
				this.hideForm();
			},
			restore: function(){
				this.setBtnStatus(false);
			},
			updatedata: function(){
				this.setBtnStatus(false);
			},
			createdata: function(){
				this.setBtnStatus(false);
			},
			deletedata: function(){
				this.setBtnStatus(false);
				this.setBtnVisibility(false);
				this.hideForm();
			},
			scope: this
		});
	},
	
	/**
     * Imposta sul Manager l'oggetto di controllo della mappa per intercettare le 
     * operazioni utente (eventi tolomeo) e procedere con la gestione della form.
     * @param {TolomeoExt.ToloMapAPIExt} mapApiExt Oggetto di controllo della mappa.
     */
	setMapApiExt: function(mapApiExt){
		this.codelessManager.setMapApiExt(mapApiExt);
	},
	
	/**
     * Imposta la modalità  con cui configurare la form.
     * @param {String} mode Modalità  di configurazione (view, edit, new).
     * @param {Ext.Data.Store} store Store con gui configurare la griglia dei dati
     */
	setFormMode: function(mode, store){
		this.mode = mode;
		
		if(mode == "view"){
			this.fieldSet.setTitle(this.viewFieldSetTitle);	
			this.setBtnVisibility(false);
		}else if(mode == "edit"){
			this.fieldSet.setTitle(this.editFieldSetTitle);
			this.setBtnVisibility(true);
		}if(mode == "new"){
			this.fieldSet.setTitle(this.newFieldSetTitle);
			this.setBtnVisibility(true);
		}
		
		this.propertyGrid.reconfigure(store);
		
		// ///////////////////////////////////////////////////////////
		// Se sono stati forniti dal server valori di default per i 
		// campi della form allora le rispettive celle delle griglia 
		// devono essere marcate come valorizzate (DIRTY).
		// ///////////////////////////////////////////////////////////
		if(mode == "new"){
			var gridStore = this.propertyGrid.getStore();
			var isDirty = false;
			gridStore.each(function(r) {
				var value = r.get("value");
				var nl = r.get("nl");
                if (value != "" && nl != "") {
                   r.setDirty();
                   isDirty = true;
                }
            });
            
			// Se alcuni campi sono valorizzati abilitare i pulsanti della toolbar.
			this.setBtnStatus(isDirty);
		}
		
		this.showForm();
	},
	
	/**
     * Visualizza la form dei dati.
     * @param {boolean} withDecode Stabilisce se visualizzare anche la form di decodifica.
     */
	showForm: function(){
		this.fieldSet.show();		
		this.formPanel.show();
	},
	
	/**
     * Nasconde la form dei dati.
     */
	hideForm: function(){
		this.fieldSet.hide();
		this.formPanel.hide();
	},
	
	/**
     * Imposta lo stato dei pulsanti presenti nella toolbar del pannello di modifica.
     */
	setBtnStatus: function(enabled){
		if(enabled === true){
			this.formPanel.query("button[ref=resetButton]")[0].enable();
			this.formPanel.query("button[ref=saveButton]")[0].enable();
		}else{
			this.formPanel.query("button[ref=resetButton]")[0].disable();
			this.formPanel.query("button[ref=saveButton]")[0].disable();
		}
	},
	
	/**
     * Imposta la visibilità dei pulsanti presenti nella toolbar del pannello di modifica.
     */
	setBtnVisibility: function(visible){
		if(visible === true){
			this.formPanel.query("button[ref=saveButton]")[0].show();
			this.formPanel.query("button[ref=resetButton]")[0].show();
		}else{
			this.formPanel.query("button[ref=saveButton]")[0].hide();
			this.formPanel.query("button[ref=resetButton]")[0].hide();
		}
	}
    
});

/**
 * Plugin per la gestione di richieste e operazioni 
 * che coinvolgono la form codeless.
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.ToloViewCodelessManager', {
	
	extend: 'Ext.util.Observable',
	
	id: "cl_manager",
	
	/**
	 * @cfg {String} TOLOMEOServer
	 * URL di base del contesto di Tolomeo.
	 */
	TOLOMEOServer: null,
	
	/**
	 * @cfg {String} TOLOMEOContext
	 * Contesto di Tolomeo.
	 */
	TOLOMEOContext: null,
	
	/**
	 * @property {TolomeoExt.ToloMapAPIExt} mapApiExt
	 * Oggetto di controllo della mappa.
	 */
	
	/**
	 * @cfg {Ext.data.Store} store
	 * Store dei dati su cui agisce il manager.
	 */
	
	/**
	 * @property {String} updateDialogTitle
	 * Titolo da mostrare per la dialog di aggiornemnto dati.
	 */
    updateDialogTitle: null,
    
	/**
	 * @property {String} updateDialogText
	 * Testo da mostrare all'interno della dialog di aggiornemnto dati.
	 */
    updateDialogText: null,
    
	/**
	 * @property {String} deleteDialogTitle
	 * Titolo da mostrare per la dialog di cancellazione dati.
	 */
    deleteDialogTitle: null,
    
	/**
	 * @property {String} deleteDialogText
	 * Testo da mostrare all'interno della dialog di cancellazione dati.
	 */
    deleteDialogText: null,

	/**
     * Crea un nuovo TolomeoExt.ToloViewCodelessManager.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	constructor: function(config) {
		
	    updateDialogTitle = ToloI18n.getMsg("ToloViewCodelessManager.updateDialogTitle");
	    updateDialogText = ToloI18n.getMsg("ToloViewCodelessManager.updateDialogText");
	    deleteDialogTitle = ToloI18n.getMsg("ToloViewCodelessManager.deleteDialogTitle");
	    deleteDialogText = ToloI18n.getMsg("ToloViewCodelessManager.deleteDialogText");

		this.callParent(arguments);
		
		Ext.apply(this, config);
		
		this.addEvents(
	        /**
			 * @event
			 * Lanciato alla fallimento della richiesta.
			 */
			"loaddatafailure",
	        /**
			 * @event
			 * Lanciato prima di effettuare la richiesta di aggiornamento dati.
			 */
			"beforeupdatedata",
	        /**
			 * @event
			 * Lanciato prima di effettuare la richiesta di caricamento dati.
			 */
			"beforeloaddata",
	        /**
			 * @event
			 * Lanciato al termine della richiesta di caricamento se questa è andata a buon fine.
			 */
			"loaddata",
	        /**
			 * @event
			 * Lanciato al termine della richiesta di aggiornamento se questa è andata a buon fine.
			 */
			"updatedata",
	        /**
			 * @event
			 * Lanciato prima di effettuare la richiesta di cancellazione dei dati.
			 */
			"beforedeletedata",
	        /**
			 * @event
			 * Lanciato al termine della richiesta di cancellazione se questa è andata a buon fine.
			 */
			"deletedata",
	        /**
			 * @event
			 * Lanciato prima di effettuare la richiesta di creazione di una feature.
			 */
			"beforecreatedata",
	        /**
			 * @event
			 * Lanciato al termine della richiesta di creazione di una nuova feature se questa è andata a buon fine.
			 */
			"createdata",
	        /**
			 * @event
			 * Lanciato a seguito della selezione di una feature in mappa.
			 */
			"objectselected",
	        /**
			 * @event
			 * Lanciato a seguito del cambio di modalità di funzionamento (edit, view o new)
			 */
			"changemode",
	        /**
			 * @event
			 * Lanciato a seguito del ripristino dello store ai valori iniziali
			 */
			"restore"
		);	
	},
	
	/**
     * Imposta l'oggetto di controllo della mappa per intercettare le 
     * operazioni utente (eventi tolomeo) e procedere con la gestione della form.
     * @param {TolomeoExt.ToloMapAPIExt} mapApiExt oggetto di controllo della mappa.
     */
	setMapApiExt: function(mapApiExt){
		this.mapApiExt = mapApiExt;

		this.mapApiExt.on({
			viewcodelessaction: function(eventoLayer, object){
				this.selection = object;
				
				// /////////////////////////////////////////////
				// Caricamento di tutte le informazioni al 
				// fine di preparare la griglia per la modalità
				// di visualizzazione
				// /////////////////////////////////////////////
				var fparams = {
					codTPN: this.selection.codTPN,
					command: "view",
					IDTPN: this.selection.key,
					paramPreset: TolomeoExt.Vars.paramsJS.nomePreset
				}; 
				
				this.loadViewMode(fparams);
			},	
			onObjectSelect: function(){
				this.fireEvent("objectselected");
			},
			scope: this
		});
	},
	
	/**
     * Imposta la modalità  di funzionamento del manager.
     * @param {String} mode Modalità  di configurazione (view, edit, new).
     * @param {Ext.Data.Store} store Store da usare per componenti di tipo UI
     */
	setMode: function(mode, store){
		this.store = store;
		this.fireEvent("changemode", mode, store);
	},
	
	/**
     * Handler invocato in caso di fallimento della richiesta Ajax.
     * @param {Ext.Data.Store} store Oggetto rappresentante lo store dei dati. 
     *
     */
	doAjaxFailure: function (store) {
		this.fireEvent("loaddatafailure", store);
    },
    
    /**
     * Metodo di caricamento dello store delle features per la modalità 'view'.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    loadViewMode: function(fparams){       	
    	this.fireEvent("beforeloaddata");
    	
		this.request(
			fparams,
			"GET",
    		function(results, store){
				this.setMode("view", store);
    			this.fireEvent("loaddata", store);
    		},
    		this.doAjaxFailure,
    		this
		);
    },
    
    /**
     * Metodo di caricamento dello store delle features per la modalità 'edit'.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    loadEditMode: function(fparams, isNew){       	
    	this.fireEvent("beforeloaddata");
    	
		this.request(
			fparams,
			"GET",
    		function(results, store){
				var mode = "edit";
				// //////////////////////////////////////////////////////////////
				// Controlla se stiamo cercando di creare un nuovo elemento o no 
				// //////////////////////////////////////////////////////////////
				if(isNew){
					mode = "new";
				}
				
				this.setMode(mode, store);
    			this.fireEvent("loaddata", store);
    		},
    		this.doAjaxFailure,
    		this
		);
    },
    
    /**
     * Metodo di aggiornamento dei dati.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    update: function(fparams){
    	this.fireEvent("beforeupdatedata");
    	
    	var updatedRecords = this.store.getUpdatedRecords();
    	
    	if(updatedRecords.length > 0){
    		var params = Ext.applyIf(
				{
					codTPN: this.selection.codTPN,
					command: "update",
					IDTPN: this.selection.key
				}, 
				fparams
			); 
    		
    		var data = "[";
    		for(var i=0; i<updatedRecords.length; i++){
    			var record = updatedRecords[i];
    			var values = record.data;
    			data += Ext.encode(values);
    			
    			if(i+1 != updatedRecords.length){
    				data += ",";
    			}
    		}
    		data += "]";
    		
    		params.data = data;
    		
    		this.request(
				params,
				"POST",
				function(results, store){
					// /////////////////////////////////////////////////
					// Ridisegna il layer per aggiornare lo stato di 
					// eventiali etichette che sono state modificate 
					// durante la procedura di aggiornamento.
					// /////////////////////////////////////////////////
					this.mapApiExt.viewer.pluginRefreshMap();
					
					this.setMode("edit", store);
	    			this.fireEvent("updatedata", store);
	    		},
	    		this.doAjaxFailure,
	    		this
    		);
    	}else{
            Ext.Msg.show({
                title: this.updateDialogTitle,
                msg: this.updateDialogText,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.INFO
            }); 
    	}
    },
    
    /**
     * Metodo di cancellazione dei dati.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    cancel: function(fparams){
    	this.fireEvent("beforedeletedata");
    	
		this.request(
			fparams,
			"POST",
    		function(results){
				if(results){
					// /////////////////////////////////////////////////
					// Ridisegna il layer per aggiornare lo stato di 
					// eventiali etichette che sono state modificate 
					// durante la procedura di aggiornamento.
					// /////////////////////////////////////////////////
					this.mapApiExt.viewer.pluginRefreshMap();
					
					this.fireEvent("deletedata", results);
					
					// ////////////////////////////////////
					// Informa l'utente che l'operazione è 
					// stata completata con successo.
					// ////////////////////////////////////
		            Ext.Msg.show({
		                title: this.deleteDialogTitle,
		                msg: results[0].data.Descrizione,
		                buttons: Ext.Msg.OK,
		                icon: Ext.MessageBox.INFO
		            }); 
				}			
    		},
    		this.doAjaxFailure,
    		this
		);
    },
    
    /**
     * Metodo per la raccolta dati al fine di creare un nuovo elemento.
     * @param {Object} fparams Oggetto contenente i parametri che saranno usati nella richista. 
     *
     */
    create: function(fparams){
    	this.fireEvent("beforecreatedata");
    	var updatedRecords = this.store.getUpdatedRecords();
    	
    	if(updatedRecords.length > 0){
    		var params = Ext.applyIf(
				{
					codTPN: this.selection.codTPN,
					command: "new",
					SRID: this.selection.SRID,
					geometry: this.selection.geometry
				}, 
				fparams
			); 
    		
    		var data = "[";
    		for(var i=0; i<updatedRecords.length; i++){
    			var record = updatedRecords[i];
    			var values = record.data;
    			data += Ext.encode(values);
    			
    			if(i+1 != updatedRecords.length){
    				data += ",";
    			}
    		}
    		data += "]";
    		
    		params.data = data;
    		
    		this.request(
				params,
				"POST",
				function(results, store){
					// /////////////////////////////////////////////////
					// Ridisegna il layer per aggiornare lo stato di 
					// eventiali etichette che sono state modificate 
					// durante la procedura di aggiornamento.
					// /////////////////////////////////////////////////
					this.mapApiExt.viewer.pluginRefreshMap();
					
					this.setMode("edit", store);
	    			this.fireEvent("createdata", store);
	    		},
	    		this.doAjaxFailure,
	    		this
    		);
    	}else{
            Ext.Msg.show({
                title: this.updateDialogTitle,
                msg: this.updateDialogText,
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.INFO
            }); 
    	}
    },
    
    /**
     * Metodo di gestione della richiesta Ajax.
     */    
    request: function(params, method, success, failure, scope){
    	var submitOpt = {
    		url: this.TOLOMEOServer + this.TOLOMEOContext + '/LayerItemViewServlet',
    		method: method,
    		params: params,
    		success: success,
    		failure: failure ? failure : this.doAjaxFailure,
    		scope: scope
    	};
    	
		new TolomeoExt.ToloCrossAjax().request(submitOpt);
    },
    
    /**
     * Restituisce i metadati della richiesta.
     */  
    getRequestMetadata: function(store){
    	var gridStore = store || this.store;
		var proxy = gridStore.getProxy();
		var reader = proxy.getReader();
		var metadata = reader.metaData;
		
		return metadata;
    },
    
    /**
     * Ripristina i dati nello store eliminando le modifiche.
     *
     */
    restore: function(){
    	this.store.rejectChanges();
    	this.fireEvent("restore");
    }
	
});
/**
 * Strumento di visualizzazione ed editing dei dati configurabile, 
 * senza la necessità di scrivere codice (“codeless”) per Tolomeo. 
 *
 * @author Tobia Di Pisa at tobia.dipisa@geo-solutions.it
 */
Ext.define('TolomeoExt.ToloViewCodeLessPanel', {

	extend: 'Ext.Panel',

	/**
	 * @cfg {Object} paramsJS
	 * Configurazioni specifiche del file di preset.
	 */
	paramsJS: null,

	/**
	 * @cfg {String} TOLOMEOServer
	 * URL di base del contesto di Tolomeo.
	 */
	TOLOMEOServer: null,

	/**
	 * @cfg {String} TOLOMEOContext
	 * Contesto di Tolomeo.
	 */
	TOLOMEOContext: null,
	
	/**
	 * @cfg {String} viewFieldSetTitle
	 * Testo del field set in modalit� di visualizzazione.
	 */
	viewFieldSetTitle: null, //"Visualizzazione Dati",
	
	/**
	 * @cfg {String} editFieldSetTitle
	 * Testo del field set in modalità di modifica.
	 */
	editFieldSetTitle: null,
	
	/**
	 * @cfg {String} newFieldSetTitle
	 * Testo del field set in modalità di nuovo elemento.
	 */
	newFieldSetTitle: null,
	
	/**
	 * @cfg {String} applyModsTooltip
	 * Testo da mostrare per il tootlip del pulsante di salvataggio delle modifiche.
	 */
	applyModsTooltip: null,
	
	/**
	 * @cfg {String} resetTooltip
	 * Testo da mostrare per il tootlip del pulsante di reset delle modifiche.
	 */
	resetTooltip: null,
	
	/**
	 * @cfg {String} restoreBoxTitle
	 * Titolo da mostrare per la dialog di conferma per il reset delle modiche.
	 */
	restoreBoxTitle: null, 
	
	/**
	 * @cfg {String} restoreBoxText
	 * Testo da mostrare per la dialog di conferma per il reset delle modiche.
	 */
	restoreBoxText: null, 

	/**
	 * @cfg {String} saveBoxTitle
	 * Titolo da mostrare per la dialog di conferma per il salvataggio delle modiche.
	 */
	saveBoxTitle: null, 
	
	/**
	 * @cfg {String} saveBoxText
	 * Testo da mostrare per la dialog di conferma per il salvataggio delle modiche.
	 */
	saveBoxText: null, 
	
	/**
	 * @cfg {String} missingIDTPNTitle
	 * Titolo da mostrare in fase di salvataggio se il campo relativo all'IDTPN non risulta valorizzato.
	 */
	missingIDTPNTitle: null, 
	
	/**
	 * @cfg {String} missingIDTPNText
	 * Testo da mostrare per la dialog di avviso in fase di salvataggio se il campo relativo all'IDTPN non risulta valorizzato.
	 */
	missingIDTPNText: null, 
	
	/**
     * @cfg {Object} autoCompleteCfg [autoCompleteCfg="{}"]
	 * Stabilisce la configurazione da usare per la funzionalità di autocompletamento.
	 *
	 * @example
	 * autoCompleteCfg: {
	 *  	url: 'http://localhost:8080/tolomeobinj/UniqueValueServlet',
	 *		pageSize: 10
	 * }
     */
    autoCompleteCfg: {},
    
	/**
	 * @cfg {Number} pageSize
	 * Indica il massimo numero di elementi per pagina per la combo di autocompletamento usato per 
	 * gli editor di FKs.
	 */
    pageSize: 10,
    
	/**
	 * @cfg {String} dateFormat [dateFormat="c"]
	 * Indica il formato per i campi editor di tipo "data" (il valore predefinito e 'c' che corrispondea 'ISO 8601 date').
	 */
    dateFormat: "c",
    
	/**
	 * @cfg {Array} dateFormats
	 * Formati di data ExtJS disponibili per gli editor di campi data di questo componente.
	 */
    dateFormats: [
        {java: "yyyy-MM-dd'T'HH:mm:ss", ext: "Y-m-d H:i:s"},
        {java: "yyyy-MM-dd", ext: "Y-m-d"},
        {java: "dd-MM-yyyy", ext: "d-m-Y"},
        {java: "dd-MM-yyyy", ext: "d-m-Y"},
        {java: "MM-dd-yyyy", ext: "m-d-Y"}		
    ],
    
	/**
	 * @property {TolomeoExt.ToloViewCodelessManager} codelessManager
	 * Gestore delle operazioni del componente.
	 */
	
	/**
	 * @property {Ext.grid.Panel} propertyGrid
	 * Griglia ExtJs per la presentazione e la modifica dei dati richiesti.
	 */
	
	/**
	 * @property {Ext.grid.Panel} decodeGrid
	 * Griglia ExtJs per la presentazione e la modifica dei dati relativi alle tabelle di decodifica.
	 */
	
	/**
	 * @property {String} mode
	 * Stringa che indica la modalità di funzionamento corrente della form.
	 */

	/**
     * Inizializza un nuovo TolomeoExt.ToloNewCodeLessPanel.
     * @param {Object} [config] Un opzionale oggetto di configurazione per il componente ExtJs.
     */
	initComponent: function(config){
		TolomeoExt.Vars.ApplyIfDefaults(this);
		
		editFieldSetTitle = ToloI18n.getMsg("ToloViewCodeLessPanel.editFieldSetTitle");
		newFieldSetTitle = ToloI18n.getMsg("ToloViewCodeLessPanel.newFieldSetTitle");
		applyModsTooltip = ToloI18n.getMsg("ToloViewCodeLessPanel.applyModsTooltip");
		resetTooltip = ToloI18n.getMsg("ToloViewCodeLessPanel.resetTooltip");
		restoreBoxTitle = ToloI18n.getMsg("ToloViewCodeLessPanel.restoreBoxTitle"); 
		restoreBoxText = ToloI18n.getMsg("ToloViewCodeLessPanel.restoreBoxText"); 
		saveBoxTitle = ToloI18n.getMsg("ToloViewCodeLessPanel.saveBoxTitle"); 
		saveBoxText = ToloI18n.getMsg("ToloViewCodeLessPanel.saveBoxText");
		missingIDTPNTitle = ToloI18n.getMsg("ToloViewCodeLessPanel.missingIDTPNTitle"); 
		missingIDTPNText = ToloI18n.getMsg("ToloViewCodeLessPanel.missingIDTPNText"); 

		
		// ///////////////////// //
		// FEATURE DI SELEZIONE  //
		// ///////////////////// //
		
		var gridStore = Ext.create('Ext.data.Store', {
		    fields: ["name", "nl", "type", "editable", "validation", "value", "value2", "format", "width"],
		    proxy: {
		        type: 'memory',
		        reader: {
		            type: 'json',
		            root: 'rows'
		        }
		    }
		});
		
	    var me = this;
		this.propertyGrid = Ext.create('Ext.grid.Panel', {
			margin: "5 5 5 5",
			hideHeaders: true,
			store: gridStore,
			overflowY: 'auto',
		    columns: [
              {
            	  header: ToloI18n.getMsg("ToloViewCodeLessPanel.colNome"),  
            	  dataIndex: 'name',
            	  tdCls: 'codelessnomecampo',
            	  flex: 1,
            	  renderer: function(value, metaData, record, rowIndex, colIndex, store, view)
            	  {
            		  var type = record.get("type");
            		  
	  	              switch (type) {
	                    case "VALORE":
	                    	return value;
	                        break;
	                    case "COSTANTE":
						    metaData.tdAttr = ' colspan="2"';
	                    	return value;
	                        break;
	                    case "URL":
						    metaData.tdAttr = ' colspan="2"';
	                    	return "<a href=\"" + record.get("value") + "\" target=\"_blank\">" + value + "</a>";
	                        break;
	                    case "IMG":
						    metaData.tdAttr = ' colspan="2"';
	                    	return "<img src=\"" + record.get("value") + "\" alt=\"" + value + "\" width=\"" + record.get("width") + "\"></img>";
	                        break;
	                    case "IMGURL":
						    metaData.tdAttr = ' colspan="2"';
	                    	return "<a href=\"" + record.get("value2") + "\" target=\"_blank\"><img src=\"" + record.get("value") + "\" alt=\"" + value + "\" width=\"" + record.get("width") + "\"></img></a>";
	                        break;
	                    case "DETAIL":
	                    	return value;
	                        break;
	                    default:
	                		return value;
	  	              }
            	  }
              },
              {
            	  header: 'NL',  
            	  dataIndex: 'nl',
                  hidden: true
              },
              {
            	  header: 'Tipo',  
            	  dataIndex: 'type',
                  hidden: true
              },
              {
            	  header: 'Editabile',  
            	  dataIndex: 'editable',
                  hidden: true
              },
              {
            	  header: 'Validation',  
            	  dataIndex: 'validation',
                  hidden: true
              }, 
              {
            	  header: ToloI18n.getMsg("ToloViewCodeLessPanel.colValore"), 
            	  dataIndex: 'value',
            	  tdCls: 'codelessvalore',
            	  //flex: 50/100,
            	  flex: 2,
            	  renderer: function(value, metaData, record, rowIndex, store, view) {
            		  var type = record.get("type"); 
	  	              switch (type) {
	                    case "VALORE":
	                    	return value;
	                        break;
	                    case "COSTANTE":
	                    case "URL":
	                    case "IMG":
	                    case "IMGURL":
	                    	return null;
	                        break;
	                    case "DETAIL":
	                    	return value;
	                        break;
	                    default:
	                		return value;
	  	              }
            	  }
              }
            ]
		});
		
	    this.layout = 'fit';
		
		this.callParent();
		this.buildManager(gridStore);
//		this.codelessManager.on("loaddata", this.dataLoaded, this);
		
		this.add([this.propertyGrid]);
	},
	
//	dataLoaded: function()
//	{
//		
//		var linkButton = this.formPanel.query("button[ref=linkButton]")[0];
//		var metadata = this.codelessManager.getRequestMetadata();
//		
//		if (metadata.layerURL != null && metadata.layerURL != "") {
//			linkButton.setText(metadata.layerURLLabel);
//			linkButton.setHref(metadata.layerURL);
//			linkButton.show();
//		} else {
//			linkButton.hide();
//		}
//	},
	
	/**
     * Restituisce il formato data da usare per l'editor. 
     * 
     */
	getDateFormat: function(){
		var metadata = this.codelessManager.getRequestMetadata();
    	
		// ////////////////////////////////////////////////////////////
		// Usa ISO-8601 come formato data se non viene trovata nessuna 
		// corrispondenza attraverso l'invocazione di getExtDateFormat.
		// ////////////////////////////////////////////////////////////
		var format =  metadata ? (this.getExtDateFormat(metadata.dateFormat) || this.dateFormat) : this.dateFormat;
		return format;
	},
	
	/**
     * Converte il formato Data fornito dal server sulla base di quelli disponibili 
     * in configurazione. 
     * @param {String} format formato da usare per il campo editor della data.
     * 
     */
	getExtDateFormat: function(format){
		var date_format;
		
		if(format){
			for(var i=0; i<this.dateFormats.length; i++){
				var df = this.dateFormats[i];
				if(format == df.java){
					date_format = df.ext;
					break;
				}
			}
		}
		
		return date_format;
	},
	
	/**
     * Crea il componente Ext destinato a contenere il valore delle propriet�.
     * @param {TolomeoExt.data.ToloUniqueValuesStore} store Store della combo box di auto completamento.
     * @param {String} url Url del servizio remoto di auto completamento.
     * @param {String} layerName codTPN da usare com eparametro della richiesta.
     * @param {String} fieldName Nome della proprietà di cui ritornare i suggerimenti.
     * 
     */
    initUniqueValuesStore: function(store, layerName, fieldName) {
        var params = {
            inputs: {
            	featureTypeName: layerName,
                fieldName: fieldName
            },
            start: 0,
            limit: this.autoCompleteCfg.pageSize || this.pageSize
        };
        
        store.setParams(params);
    },
	
	/**
     * Crea il Gestore delle richieste se assente e registra gli eventi necessari.
     * @param {Ext.Data.Store} store Store che il Manager deve gestire.
     */
	buildManager: function(store){
		this.codelessManager = Ext.create('TolomeoExt.ToloViewCodelessManager', {
			TOLOMEOServer : this.TOLOMEOServer,
			TOLOMEOContext: this.TOLOMEOContext,
			store: store
		});
		
		this.codelessManager.on({
			changemode: function(mode, store){
				this.setFormMode(mode, store);
			},
			scope: this
		});
	},
	
	/**
     * Imposta sul Manager l'oggetto di controllo della mappa per intercettare le 
     * operazioni utente (eventi tolomeo) e procedere con la gestione della form.
     * @param {TolomeoExt.ToloMapAPIExt} mapApiExt Oggetto di controllo della mappa.
     */
	setMapApiExt: function(mapApiExt){
		this.codelessManager.setMapApiExt(mapApiExt);
	},
	
	/**
     * Imposta la modalit� con cui configurare la form.
     * @param {String} mode Modalit� di configurazione (view, edit, new).
     * @param {Ext.Data.Store} store Store con gui configurare la griglia dei dati
     */
	setFormMode: function(mode, store){
		this.mode = mode;
		
		this.propertyGrid.reconfigure(store);
		
		// ///////////////////////////////////////////////////////////
		// Se sono stati forniti dal server valori di default per i 
		// campi della form allora le rispettive celle delle griglia 
		// devono essere marcate come valorizzate (DIRTY).
		// ///////////////////////////////////////////////////////////
		if(mode == "new"){
			var gridStore = this.propertyGrid.getStore();
			var isDirty = false;
			gridStore.each(function(r) {
				var value = r.get("value");
				var nl = r.get("nl");
                if (value != "" && nl != "") {
                   r.setDirty();
                   isDirty = true;
                }
            });
		}
	}
});