g_win_oem_key_map =
{
  187:  43,//VK_OEM_PLUS
  188: 44,//VK_OEM_COMMA
  189: 45,//VK_OEM_MINUS
  190: 46,//VK_OEM_PERIOD
}



var PanZoom =
{
  svgNS: 'http://www.w3.org/2000/svg',
  stateOrigin: null,
  state:'none',
  is_active: false, //used by external ui
  focus_element_name: null,
  selection_names: [],
  current_selection_controls : [],
  selection_callback: function(selected_controls) {},

  create: function()
  {

      this.svg_document = document.getElementById("char_picker").getSVGDocument();
      this.svg_element = this.svg_document.getElementsByTagName("svg")[0];


      //this.svg_element.setAttribute("style","overflow:hidden");
      this.svg_element.removeAttribute("viewBox");
      this.viewport = this.svg_document.createElementNS(this.svgNS, 'g');
      this.viewport.setAttribute('id', "viewport");


      this.fixed_viewport = this.svg_document.createElementNS(this.svgNS, 'g');
      var svgChildren = this.svg_element.childNodes;
      if (!!svgChildren && svgChildren.length > 0) {
        for (var i = svgChildren.length; i > 0; i--) {
          // Move everything into viewport except defs
          var classList = svgChildren[svgChildren.length - i].classList;
          if(svgChildren[svgChildren.length - i].nodeName !== 'defs')
          {
              var child = svgChildren[svgChildren.length - i];
              this.viewport.appendChild(child);
          }
        }
      }

      this.defs = this.svg_document.getElementsByTagName("defs")[0];

      var pattern = this.svg_document.createElementNS(this.svgNS, 'pattern');
      this.defs.appendChild(pattern);
      pattern.setAttribute("id", "error_pattern");
      pattern.setAttribute("width", "3");
      pattern.setAttribute("height", "10");
      pattern.setAttribute("patternUnits", "userSpaceOnUse");
      pattern.setAttribute("patternTransform", "rotate(45 50 50)");

      var line = this.svg_document.createElementNS(this.svgNS, 'line');
      pattern.appendChild(line);
      line.setAttribute("stroke", "#ff4e4e");
      line.setAttribute("stroke-width", "3px");
      line.setAttribute("y2", "10");


      this.select_rect = this.svg_document.createElementNS(this.svgNS, 'rect');
      this.select_rect.setAttribute('id', "select_rect");
      this.select_rect.setAttribute('style', "fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.3142668;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:5.25706742, 2.62853371000000010;stroke-dashoffset:0;stroke-opacity:0.75;display:none");
      //console.log(this.select_rect);
      this.svg_element.appendChild(this.viewport);
      this.viewport.appendChild(this.select_rect);

      this.lastMouseWheelEventTime = Date.now();
      var that = this;

      this.event_listeners = {
        mousedown: function(evt)
        {
            if (off_select == true){
                return;
            };
            that.mousedown(evt);
        },

        mouseup: function(evt)
        {
            if (off_select == true){
                return;
            };
            that.mouseup(evt);

        },
        mousemove: function(evt)
        {
              that.mousemove(evt);
        },
        contextmenu: function(evt)
        {
          that.contextmenu(evt);
        },
        keydown: function(evt)
        {
            that.keydown(evt);
        },
        wheel: function(evt)
        {
          that.wheel(evt);
        }
      };

      for (var event in this.event_listeners)
      {
              this.svg_element.addEventListener(event, this.event_listeners[event], false);
      }



      //improve select rect behaviour when we go out of window
      window.addEventListener("mousemove", this.event_listeners.mousemove, false);
      window.addEventListener("mousedown", this.event_listeners.mousedown, false);
      window.addEventListener("mouseup", this.event_listeners.mouseup, false);





      // We have bug if keydown are not set if last focus was on other iframe
      // so we need to force it on all iframes in document
      document.body.addEventListener("keydown", this.event_listeners.keydown, false);
        var embeds = document.querySelectorAll("embed");
        for (var i = 0; i < embeds.length; i++)
        {
            var callback = function(embed)
            {
                embed.getSVGDocument().children[0].addEventListener("keydown", that.event_listeners.keydown, false);

                //additionaly improve select rect behaviour when we mousemove on embeds
                embed.getSVGDocument().children[0].addEventListener("mousemove", that.event_listeners.mousemove, false);
                embed.getSVGDocument().children[0].addEventListener("mousedown", that.event_listeners.mousedown, false);
                embed.getSVGDocument().children[0].addEventListener("mouseup", that.event_listeners.mouseup, false);
            };

            if (embeds[i].getSVGDocument() == null)
            {
                embeds[i].addEventListener("load", callback.bind(this, embeds[i]));
            }
            else
            {
                callback(embeds[i]);
            }

        }




      $(document).contextmenu(function(evt){evt.preventDefault()});
      $(window).resize({pan_zoom: this},function (evt)
        {
            evt.data.pan_zoom.window_resize();
        });

        this.window_resize();
  },
  getEventPoint:function(evt)
  {
    var point = this.svg_element.createSVGPoint();
    point.x = evt.clientX;
    point.y = evt.clientY;
    return point;
  },

  parse_matrix: function(str)
  {
    arr = str.replace("matrix(", "").replace(")","").split(",").map(parseFloat);
    var matrix = this.svg_element.createSVGMatrix();

    matrix.a = arr[0];
    matrix.b = arr[1];
    matrix.c = arr[2];
    matrix.d = arr[3];
    matrix.e = arr[4];
    matrix.f = arr[5];
    return matrix;
  },
  resize_fit: function()
  {
    if(this.focus_element_name == null)
    {

        this.fit_view_to_rect(this.viewport.getBoundingClientRect(), null, null);
    }
    else
    {
        this.fit_view_to_control(this.focus_element_name, null, null);
    }
  },
  window_resize: function()
  {
      if (window.options_focus_on_resize == true)
      {
          this.resize_fit();
      }
      //this.fit_view_to_rect(view, null, null, this.fixed_viewport);
  },
  focus_selection: function()
  {
    if(this.selection_names.length > 0)
    {
        var bound_box =
        {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0,
          width: 0,
          height: 0
        };
        for(var i = 0; i < this.selection_names.length; i++)
        {
            var element = this.svg_document.getElementById(this.selection_names[i]);
            if (i == 0)
              bound_box = element.getBoundingClientRect();
            else
              bound_box = this.sum_rect(bound_box, element.getBoundingClientRect());
        }
        this.fit_view_to_rect(bound_box, null, 3);
    }
    else
    {
      this.fit_view_to_rect(this.viewport.getBoundingClientRect(), null, null);
    }
  },
  is_element_visible:function(element)
  {
      var bound_box = this.transform_rect(element.getBoundingClientRect(), this.viewport.getCTM());
      var view = this.viewport.getBoundingClientRect();
      return this.rect_intersect(view, bound_box);
  },
  keydown: function (evt)
  {
      var keyCode = evt.keyCode;
      if (keyCode in g_win_oem_key_map)
          keyCode = g_win_oem_key_map[keyCode];
      maya.call_key_event(keyCode, evt.shiftKey, evt.ctrlKey, evt.altKey);
  },
  mousedown: function(evt)
  {

    if(evt.altKey && evt.button == 1)
    {
      evt.preventDefault();
      this.firstEventCTM = this.viewport.getCTM();
      this.stateOrigin = this.getEventPoint(evt).matrixTransform(this.firstEventCTM.inverse());
      this.state = 'pan';
      this.svg_element.style.cursor = "move";
      this.is_active = true;
    }
    else if(evt.altKey && evt.button == 2)
    {
      evt.preventDefault();
      this.firstEventCTM = this.viewport.getCTM();
      this.stateOrigin = this.getEventPoint(evt).matrixTransform(this.firstEventCTM.inverse());
      this.state = 'zoom';
      this.is_active = true;
      this.svg_element.style.cursor = "zoom-in";
      //evt.preventDefault();
    }

    else if(evt.button == 0)
    {
      evt.preventDefault();
      var that = this;
      //setTimeout(function () {
      this.state = "start_select";
      this.firstEventCTM = this.viewport.getCTM();
      this.stateOrigin = this.getEventPoint(evt).matrixTransform(this.firstEventCTM.inverse());
      //this.is_active = true;

      //this.svg_element.style.cursor = "pointer";
            //           }, 100);
      //evt.preventDefault();

    }

  },
  mouseup: function(evt)
  {
    if( this.state == "select")
    {
      cmd = "select -r";
      if (evt.shiftKey && evt.ctrlKey)
      {
        cmd = "select -add";
      }
      else if (evt.shiftKey )
      {
          cmd = "select -tgl";
      }
      else if (evt.ctrlKey)
      {
        cmd = "select -deselect";
      }
      else if (this.current_selection_controls.length == 0)
      {
          cmd = "select -cl";
      }

      for(var i = 0; i < this.current_selection_controls.length; i++)
      {
          //this.current_selection_controls[i].classList.remove("selected");
          var control_name = picker_util.get_control_name(this.current_selection_controls[i]);
          cmd += " " + maya.add_asset_namespace(control_name);
      };
      maya.mel(cmd);
      selection_changed = true;
      this.current_selection_controls = [];

    }

    if( this.state == "pan" || this.state == "zoom" || this.state == "start_select" || this.state == "select" )
    {

        this.svg_element.style.cursor = "inherit";
        this.state = 'none';
        var that = this;
        setTimeout(function () {
                              that.is_active = false;
                           }, 100);

        this.select_rect.style.display = "none";
    }

  },
  mousemove: function(evt)
  {
    if (this.state == "pan" && evt.altKey && evt.buttons == 4)
    {
      var point = this.getEventPoint(evt).matrixTransform(this.firstEventCTM.inverse());
      var viewportCTM = this.firstEventCTM.translate(point.x - this.stateOrigin.x, point.y - this.stateOrigin.y);
      this.update_transform(this.viewport, viewportCTM);
    }
    else if (this.state == "zoom" && evt.altKey && evt.buttons == 2)
    {
      var point = this.getEventPoint(evt).matrixTransform(this.firstEventCTM.inverse());
      var delta = 1 +  (point.x - this.stateOrigin.x) / this.svg_element.getBoundingClientRect().width;
      //console.log(delta);
      var modifier = this.svg_element.createSVGMatrix().translate(this.stateOrigin.x, this.stateOrigin.y).scale(delta).translate(-this.stateOrigin.x, -this.stateOrigin.y);
      this.update_transform(this.viewport,this.firstEventCTM.multiply(modifier));
      //evt.preventDefault();
    }
    else if(this.state == "start_select")
    {

        var point = this.getEventPoint(evt).matrixTransform(this.firstEventCTM.inverse());

        if ( Math.sqrt( Math.pow( (point.x - this.stateOrigin.x), 2)  + Math.pow( (point.y - this.stateOrigin.y), 2)) >  10)
        {
          //evt.preventDefault();
          this.state = "select";
          this.svg_element.style.cursor = "pointer";
          this.is_active = true;
        }
    }
    else if (this.state == "select" && evt.buttons == 1)
    {
        for(var i = 0; i < this.current_selection_controls.length; i++)
        {
          this.current_selection_controls[i].classList.remove("selected");
        }
        this.current_selection_controls = [];
        //evt.preventDefault();
        var point = this.getEventPoint(evt).matrixTransform(this.firstEventCTM.inverse());
        var xstart = this.stateOrigin.x;
        var ystart = this.stateOrigin.y;
        var xend =   point.x;
        var yend = point.y;

        // we should swap start and end point if user will draw it inverted
        var region_xstart = xstart > xend ? xend: xstart;
		    var region_ystart = ystart > yend ? yend: ystart;
		    var region_xend = xend < xstart ? xstart: xend;
		    var region_yend = yend < ystart ? ystart: yend;

        this.select_rect.setAttribute("x" , region_xstart);
        this.select_rect.setAttribute("y" , region_ystart);
        this.select_rect.setAttribute("width" , region_xend - region_xstart);
        this.select_rect.setAttribute("height", region_yend - region_ystart);
        //console.log(point);
        this.select_rect.style.display = null;
        var selection_rect = this.transform_rect(this.select_rect.getBoundingClientRect(), this.firstEventCTM.inverse())
        //var firstEventCTM = this.firstEventCTM;

        var that = this;
        $(this.viewport).find(".control").each(
          function(index, element)
          {
              var rect = element.getBoundingClientRect();

              var scene_rect = that.transform_rect(rect, that.firstEventCTM.inverse());
              //console.log(selection_rect, scene_rect);
              if(that.rect_intersect(selection_rect, scene_rect) && !element.classList.contains("disabled") && !element.classList.contains("hidden") )
              {
                  element.classList.add("selected");
                  that.current_selection_controls.push(element);
              }
          }
        )
    }

  },
  wheel: function(evt)
  {
    var delta = evt.deltaY || 1;
    var timeDelta = Date.now() - this.lastMouseWheelEventTime;
    var divider = 3 + Math.max(0, 30 - timeDelta)

    // Update cache
    this.lastMouseWheelEventTime = Date.now();
    if ('deltaMode' in evt && evt.deltaMode === 0 && evt.wheelDelta)
    {
        delta = evt.deltaY === 0 ? 0 :  Math.abs(evt.wheelDelta) / evt.deltaY
    }

      delta = -0.3 < delta && delta < 0.3 ? delta : (delta > 0 ? 1 : -1) * Math.log(Math.abs(delta) + 10) / divider;

      var point = this.getEventPoint(evt).matrixTransform(this.viewport.getScreenCTM().inverse());
      var zoom = Math.pow(1 + 0.1, (-1) * delta);

      var relative_point = point.matrixTransform( this.viewport.getCTM().inverse() );
      var modifier = this.svg_element.createSVGMatrix().translate(relative_point.x, relative_point.y).scale(zoom).translate(-relative_point.x, -relative_point.y);
      this.update_transform(this.viewport, this.viewport.getCTM().multiply(modifier));
  },
  contextmenu: function(evt)
  {
    evt.preventDefault();
  },
  fit_view_to_control:function(control_name)
  {
    var element = this.svg_document.getElementById(control_name);
    var bound = element.getBoundingClientRect();
    this.fit_view_to_rect(bound, null, null);
  },
  sum_rect: function(lhs, rhs)
  {
      var lhs_point_x = Math.min(lhs.left, rhs.left);
      var lhs_point_y = Math.min(lhs.top, rhs.top);

      var rhs_point_x = Math.max(lhs.right, rhs.right);
      var rhs_point_y = Math.max(lhs.bottom, rhs.bottom);

      return {
                left: lhs_point_x,
                top: lhs_point_y,
                right: rhs_point_x,
                bottom:rhs_point_y,
                width: rhs_point_x - lhs_point_x,
                height: rhs_point_y - lhs_point_y
              }
  },
  transform_rect: function(rect, matrix)
  {
    var left_point = this.svg_element.createSVGPoint();
    left_point.x = rect.left;
    left_point.y = rect.top;

    var right_point = this.svg_element.createSVGPoint();
    right_point.x = rect.right;
    right_point.y = rect.bottom;
    left_point = left_point.matrixTransform(matrix);
    right_point = right_point.matrixTransform(matrix);


    return {
              left: left_point.x,
              top: left_point.y,
              right: right_point.x,
              bottom:right_point.y,
              width: right_point.x - left_point.x,
              height: right_point.y - left_point.y
            }

  },

  fit_view_to_rect: function(rect, min_scale, max_scale)
  {
      var pos_x = rect.left  + rect.width /2;
      var pos_y = rect.bottom + rect.height /2;

      var view = this.svg_element.getBoundingClientRect();

      var scene_space_rect = this.transform_rect(rect, this.viewport.getScreenCTM().inverse() );

      var view_width = view.width;
      var view_height = view.height - view.height * 0.05;
      var x_ratio = (view_width / scene_space_rect.width );
      var y_ratio = (view_height/ scene_space_rect.height );
      var point_x = scene_space_rect.left + scene_space_rect.width / 2;
      var point_y = scene_space_rect.top + scene_space_rect.height / 2;

      var cx = point_x - view_width / 2.0;
      var cy = point_y - view_height / 2.0;
      var scale = Math.min(x_ratio, y_ratio);

      if(min_scale != null)
      {
          scale = Math.max(scale, min_scale)
      }
      if(max_scale != null)
      {
          scale = Math.min(scale, max_scale)
      }
      var resultMatrix = this.svg_element.createSVGMatrix().translate(-cx, -cy).translate(point_x , point_y).scale(scale).translate(-point_x, -point_y);
      this.update_transform(this.viewport, resultMatrix);
  },
  update_transform: function(viewport, matrix)
  {
    var matrix_str = 'matrix(' + matrix.a + ',' + matrix.b + ',' + matrix.c + ',' + matrix.d + ',' + matrix.e + ',' + matrix.f + ')';
    viewport.setAttributeNS(null, 'transform', matrix_str);

  },
  rect_intersect:function (lhs, rhs)
  {
    var xp = lhs.left;
    var yp = lhs.top;
    var w = lhs.width;
    var h = lhs.height;

    var xp2 = rhs.left;
    var yp2 = rhs.top;
    var w2 = rhs.width;
    var h2 = rhs.height;

   var l1 = xp;
   var r1 = xp;
   if (w < 0)
       l1 += w;
   else
       r1 += w;
   if (l1 == r1) // null rect
       return false;

   var l2 = xp2;
   var r2 = xp2;
   if (w2 < 0)
       l2 += w2;
   else
       r2 += w2;
   if (l2 == r2) // null rect
       return false;

   if (l1 >= r2 || l2 >= r1)
       return false;

   var t1 = yp;
   var b1 = yp;
   if (h < 0)
       t1 += h;
   else
       b1 += h;
   if (t1 == b1) // null rect
       return false;

   var t2 = yp2;
   var b2 = yp2;
   if (h2 < 0)
       t2 += h2;
   else
       b2 += h2;
   if (t2 == b2) // null rect
       return false;

   if (t1 >= b2 || t2 >= b1)
       return false;

   return true;
  }

};
