'use strict';

var Minimap = function (parentElement, guiLoading)
{
  var _this = this;

  this.underlyingMapGui = new MapGui (this);

  this.$minimap_elem = $('<div id="mapDiv" class="onscreenGui onscreenGuiElement minimap"></div>');
  parentElement.append (this.$minimap_elem);

  gui.disablePickingCaptionWhenMouseOver (this.$minimap_elem);

  this.$minimapTwin_elem = $('<div class="'+this.$minimap_elem.attr("class")+'"></div>');

  gui.disablePickingCaptionWhenMouseOver (this.$minimapTwin_elem);

  // open Big map when user clicks on the minimap
  this.$minimapTwin_elem.click (function(event)
  {
    // gui.mapDialog.openDialog();
  });

  parentElement.append (this.$minimapTwin_elem); // (note: the twin element must added to the DOM after the original minimap element, so it has higher z-index)

  this.$areaCaption_elem   = $('<div id="areaCaption" class="fontOutline"></div>');

  this.$areaCaptionInfoAbove_elem = $('<div id="areaCaptionInfoAbove" class="areaCaption areaCaptionInfoAbove fontOutline" langcaption="GUI_AREA_CAPTION_INFO"></div>');

  // we need to insert the captions into one element so they are correctly placed above/below each other
  this.$areaCaptions = $('<div class="areaCaptions"></div>');
  this.$areaCaptions.append (this.$areaCaptionInfoAbove_elem);
  this.$areaCaptions.append (this.$areaCaption_elem);

  // area captions not displayed in Edge (see comments further for more info)
  if (Preferences.Browser.EDGE)
  {
	  this.$areaCaptions.hide();
  }

  // prepend to the twin element, otherwise it won't display correctly
  this.$minimapTwin_elem.append (this.$areaCaptions);

  this.hide();

  this.currentArea = null;

  this.areaMapImage = assetLoader.loadImageRawData (Preferences.Map.AREA_MAP_FILENAME, this, "areaMapImage");

  this.areaIdToNameMap = {};
  this.areaNameToOrigColorToIdMap = {};

  // marked as finished when SVG with area image is finished loading
  var areaMapLoading = assetLoader.makeDummyJob("area map SVG dom loading", true, function () {});

  // SVG DOM
  Gui.loadSvg ("areaImage", Preferences.Map.AREA_MAP_FILENAME, function (externalArguments)
  {
    var $svgWrapper = externalArguments.svgWrapper;

    /////////////////////////////////////////////////////////////////
    // AREA COLOR RETRIEVAL
    /////////////////////////////////////////////////////////////////

    // objects in map SVG have these prefix in their id's, e.g. they have id like "area_courtyard1"
    $svgWrapper.find('[id^="' + Preferences.Prefixes.SVG_AREA_MAP_LOCATION + '"]').each (function()
    {
			var t = $(this);

      // extract name of the element without prefix, i.e. "area_courtyard1" -> extract "courtyard1"
      var areaName = Util.cutPrefixFromString (t.attr('id'), Preferences.Prefixes.SVG_AREA_MAP_LOCATION);

      // extract fill color of the element in RGB and convert to an array
      var areaColor = Util.parseRGB ( t.css('fill'), true );

      // convert fill color to integer
      var areaId = renderer.colorId(areaColor);

      // save mapping from integer (which represents area's color) to the area (internal) name
      _this.areaIdToNameMap[areaId] = areaName;
    });

    // we set id 0 = background color = no area
    _this.areaIdToNameMap[0] = null;

  }, null, areaMapLoading);

  guiLoading.waitForFinish(areaMapLoading);

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // MINIMAP IMAGES LOADING
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  var minimapCreationJob = assetLoader.makeDummyJob("minimap creation", true, function () {});

  var minimapImageLoadJob = assetLoader.makeExternalLoadingJob("minimap image load");
  minimapCreationJob.waitFor (minimapImageLoadJob);
  this.$minimapImage_elem = $('<div id="map" class="minimap-image minimapImage"></div>');
  this.$minimap_elem.append ($('<div class="minimapImageBackground"></div>'));
  this.$minimap_elem.append (this.$minimapImage_elem);

 	// loads image of the triangular vision cone.
  var mapVisionConeImageLoadJob = assetLoader.makeExternalLoadingJob("minimap vision cone image load");
  minimapCreationJob.waitFor (mapVisionConeImageLoadJob);
  this.$mapVisionCone_elem = $('<img class="mapVisionCone" src="data/gui/map_view.svg" />').on ("load", function()
  {
  	mapVisionConeImageLoadJob.startJob();
  });

	// Loads image of the minimap marker.
  var markerImageLoadJob = assetLoader.makeExternalLoadingJob("marker image load");
  minimapCreationJob.waitFor (markerImageLoadJob);
  this.$minimap_elem.append (this.$mapVisionCone_elem);

  minimapCreationJob.startJob(); // execute loading of the minimap
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Called when browser window is resized.
 *
 * @private
 */
Minimap.prototype._resizeCallback = function()
{
  this.underlyingMapGui._resizeCallback();
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HIDE/UNHIDE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Makes the minimap visible.
 */
Minimap.prototype.show = function ()
{
  this.$minimap_elem.show();
  this.$minimapTwin_elem.show();
};

/**
 * Makes the minimap invisible.
 */
Minimap.prototype.hide = function ()
{
  this.$minimap_elem.hide();
  this.$minimapTwin_elem.hide();
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ZOOMING
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Zooms into the minimap.
 */
Minimap.prototype.zoomIn = function()
{
  this.underlyingMapGui.zoomIn();
};

/**
 * Zooms out the minimap.
 */
Minimap.prototype.zoomOut = function()
{
  this.underlyingMapGui.zoomOut();
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DETECTION OF CURRENT AVATAR LOCATION
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Finds name of the area at the given 2D image coordinates (image coordinate system).
 *
 * @param   {number}  imgCoordX
 * @param   {number}  imgCoordY
 * @returns {string}            name of the area under the given coordinate
 */
Minimap.prototype.findAreaAt2dCoordinatesInMap = function (imgCoordX, imgCoordY)
{
	// convert rendered pixel at camera coordinates to integer
	var areaId = renderer.colorId(Renderer.readPixelColor (this.areaMapImage, heightmapWorld.map.width, heightmapWorld.map.height, imgCoordX, imgCoordY));;
  return this.areaIdToNameMap[areaId];
};

/**
 * Finds caption of the area where the avatar currently is.
 *
 * @param   {Entity}  entity
 */
Minimap.prototype.findAreaCaption = function (entity)
{
  entity.computeHeightmapCoordinates();

  // area detection turned off in Edge due to incorrect SVG parsing
  if (Preferences.Browser.EDGE)
  {
	  return;
  }

  // (no change if the area is same or undefined - the undefined part is important! That means we have no stored are for such color.
  // The problem is that our SVG is antialiased (retarded Inkscape or GIMP are not able to save it/render it without antialiasing!!!),
  // so pixels at the areas borders are little blurred. We will treat those pixels as non-existent and assume that avatar
  // is at its last area when he is standing on such pixels. For this to work, it is important that background (i.e. where is "no area" place) is black.
  var areaName = this.findAreaAt2dCoordinatesInMap (entity.heightmapCoord.x, entity.heightmapCoord.y);

  if ((areaName === this.currentArea) || (!Util.isPropertyDefined(areaName)))
  {
    return;
  }

  this.currentArea = areaName;

  this.updateAreaCaption();
};

/**
 * Updates area caption.
 */
Minimap.prototype.updateAreaCaption = function ()
{
	this.$areaCaption_elem.text ( ContentLibrary.getContentString(this.currentArea ? this.currentArea : 'OUTSIDE') );
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// UPDATING THE MINIMAP IMAGE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Minimap.prototype.updateMinimap = function (entity)
{
  var imgCoord = this.underlyingMapGui.computeCoordinatesInMapImage (entity, true);
	var camera = appMain.getCurrentEntity().camera;
	var position = camera.getPosition();
	var translate = '';
	translate += (- position.x / 396.4980774 * 50) + '%';
	translate += ',';
	translate += (- position.z / 204.1816254 * 50) + '%';
	this.$minimapImage_elem[0].style.transform = 'translate(' + translate + ')';

  // rotate the vision cone - apply angle synchronization value and then we can rotate the cone by current camera horizontal angle
  // (the - is because this method rotates clockwise and not counter-clockwise like we are accustomed to, and we also need to convert it to degrees)
  // (IMPORTANT: image with vision cone must have set CSS propery transform-origin, so it rotates around around correct point, which is the tip of the vision cone)
	var rotation = -entity.camera.angleHorizontal + Preferences.Map.MAP_HORIZONTAL_ANGLE_SYNC_VALUE;
	rotation = Preferences.Math.RAD_TO_DEG_CONVERSION * rotation;
  this.$mapVisionCone_elem[0].style.transform = 'rotate(' + rotation + 'deg)';

  // AREA DETECTION
  this.findAreaCaption (entity);
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GETTERS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Retrieves underlying map object which contains view-projection matrix which was used to capture the map etc.
 * @returns {Map}
 */
Minimap.prototype.getUnderlyingMap = function()
{
  return this.underlyingMapGui.underlyingMap;
};
