//=============================================================================
// TMVplugin - Googleマップ遠景
// 作者: tomoaky (http://hikimoki.sakura.ne.jp/)
// Version: 1.0
// 最終更新日: 2015/12/03
//=============================================================================

/*:
 * @plugindesc Googleマップにアクセスして地図画像を取得、表示します。
 * 
 * @author tomoaky (http://hikimoki.sakura.ne.jp/)
 *
 * @param mapType
 * @desc 地図画像のタイプ
 * 初期値: hybrid（ roadmap / satellite / hybrid / terrain ）
 * @default hybrid
 *
 * @param mapZoom
 * @desc 地図画像の拡大率
 * 初期値: 12
 * @default 12
 *
 * @param mapWidth
 * @desc 地図画像の幅
 * 初期値: 512
 * @default 512
 *
 * @param mapHeight
 * @desc 地図画像の高さ
 * 初期値: 512
 * @default 512
 *
 * @param earthR
 * @desc 地球の半径（km）
 * 初期値: 6378.137
 * @default 6378.137
 *
 * @help
 *
 * 最初にプラグインコマンドの geoCoding を実行して、アクターの名前から
 * 現実世界の座標を取得します。
 * 取得が成功した状態で geoParallax を実行すれば、遠景がその座標の地図に
 * 変更されます。
 *
 * プラグインコマンド:
 *   TMGoogleMaps geoCoding 5     # アクター５番の名前でジオコーディング
 *   TMGoogleMaps geoParallax 1 2 # 直前のジオコーディング結果から遠景を変更
 *                                  数値は遠景のスクロール量（ X と Y ）
 *
 * geoCoding を実行した後、通信が完了したかどうかをチェックする必要があります。
 * チェックのためのコマンドはありませんので、イベントコマンド『スクリプト』を
 * 使用します。
 *
 * $gameTemp.isGeoCodingComplete()
 *   # geoCoding の通信が完了していれば true を返す
 *
 * $gameTemp.isGeoCodingError()
 *   # geoCoding の通信中にエラーが起きれば true を返す
 *
 * $gameTemp.isGeoDataEmpty()
 *   # geoCoding の通信の結果、座標が取得できなかった場合に true を返す
 * 
 * 上記３つのスクリプトをイベントコマンド『ループ』と『条件分岐』で使用し、
 * 通信の状態や結果を監視して、最終的に isGeoCodingComplete が true かつ
 * isGeoDataEmpty が false を返したら geoParallax を実行してください。
 *
 * おまけ機能として前回の geoCoding との距離を取得することもできます。
 * $gameTemp.getGeoDataDistance()
 * 変数に代入するなどして使用できます。前回、あるいは直前の geoCoding が
 * 失敗している場合には -1 が返ります。
 *
 * イベントコマンド『文章の表示』に距離を表示したい場合は
 * \DIST という制御文字を使えば小数点以下３桁、単位つきの距離に
 * 置き換わります。
 * getGeoDataDistance を使う必要はありません。
 *
 * 
 */

var Imported = Imported || {};
Imported.TMGoogleMaps = true;

(function() {

  var parameters = PluginManager.parameters('TMGoogleMaps');
  var mapType    = parameters['mapType'];
  var mapZoom    = parameters['mapZoom'];
  var mapWidth   = parameters['mapWidth'];
  var mapHeight  = parameters['mapHeight'];
  var earthR     = Number(parameters['earthR']);

  //-----------------------------------------------------------------------------
  // Bitmap
  //

  Bitmap.load = function(url) {
    var bitmap = new Bitmap();
    bitmap._image = new Image();
    bitmap._image.src = url;
    bitmap._image.crossOrigin = 'Anonymous';
    bitmap._image.onload = Bitmap.prototype._onLoad.bind(bitmap);
    bitmap._image.onerror = Bitmap.prototype._onError.bind(bitmap);
    bitmap._url = url;
    bitmap._isLoading = true;
    return bitmap;
  };

  //-----------------------------------------------------------------------------
  // ImageManager
  //

  ImageManager.loadGoogleBitmap = function(url) {
    var bitmap = this.loadNormalBitmap(url, 0);
    bitmap.smooth = true;
    return bitmap;
  };

  //-----------------------------------------------------------------------------
  // Game_Temp
  //

  var _Game_Temp_initialize = Game_Temp.prototype.initialize;
  Game_Temp.prototype.initialize = function() {
    _Game_Temp_initialize.call(this);
    this._geoDataLog = {};
    this.clearGeoData();
  };

  Game_Temp.prototype.clearGeoData = function() {
    if (this._geoData && !this.isGeoDataEmpty()) {
      this._geoDataLog.address = this._geoData[0][0];
      this._geoDataLog.lat = this._geoData[0][2][0];
      this._geoDataLog.lng = this._geoData[0][2][1];
    }
    this._geoStatus = 0;
    this._geoKeyword = '';
    this._geoData = [];
  };
  
  Game_Temp.prototype.setGeoStatus = function(status) {
    this._geoStatus = status;
  };
  
  Game_Temp.prototype.isGeoCodingComplete = function() {
    return this._geoStatus === 1;
  };
  
  Game_Temp.prototype.isGeoCodingError = function() {
    return this._geoStatus === -1;
  };
  
  Game_Temp.prototype.isGeoDataEmpty = function() {
    return this._geoData.length === 0;
  };
  
  Game_Temp.prototype.geoData = function() {
    return this._geoData;
  };
  
  Game_Temp.prototype.geoCoding = function(keyword) {
    this.clearGeoData();
    this._geoKeyword = keyword;
    var url = 'http://maps.google.com/maps/api/geocode/xml?address=';
    url += encodeURI(keyword) + '&sensor=false&language=ja';
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
//    if (xhr.timeout !== undefined) {
//      console.log(xhr.timeout);
//      xhr.timeout = 5000;
//    }
    xhr.onload = function() {
      if (xhr.status === 200) {
        $gameTemp.receiveGeoData(xhr.responseText);
        $gameTemp.setGeoStatus(1);
      } else {
        $gameTemp.setGeoStatus(-1);
      }
    };
    xhr.onerror = function() {
      $gameTemp.setGeoStatus(-1);
    };
    xhr.send();
  };

  Game_Temp.prototype.receiveGeoData = function(responseText) {
    var textArray = responseText.split(/\r\n|\r|\n/);
    var throughFlag = false;
    var index = 0;
    for (var i = 0, re, match; i < textArray.length; i++) {
      if (throughFlag) {
        re = /<\/address_component>/;
        match = re.exec(textArray[i]);
        if (match) {
          throughFlag = false;
        }
      } else {
        re = /<result>/;
        match = re.exec(textArray[i]);
        if (match) {
          this.setGeoData(index);
          continue;
        }
        re = /<address_component>/;
        match = re.exec(textArray[i]);
        if (match) {
          throughFlag = true;
        }
        re = /<type>(.+?)<\/type>/;
        match = re.exec(textArray[i]);
        if (match) {
          this._geoData[index][1].push(match[1])
        }
        re = /<formatted_address>(.+?)<\/formatted_address>/;
        match = re.exec(textArray[i]);
        if (match) {
          this._geoData[index][0] = match[1];
        }
        re = /<lat>(.+?)<\/lat>/;
        match = re.exec(textArray[i]);
        if (match) {
          this._geoData[index][2].push(match[1]);
        }
        re = /<lng>(.+?)<\/lng>/;
        match = re.exec(textArray[i]);
        if (match) {
          this._geoData[index][2].push(match[1]);
        }
        re = /<\/result>/;
        match = re.exec(textArray[i]);
        if (match) {
          index++;
        }
      }
    }
  };

  Game_Temp.prototype.setGeoData = function(index) {
    if (this._geoData[index] === undefined) {
      this._geoData[index] = [];
      this._geoData[index][1] = [];
      this._geoData[index][2] = [];
    }
  };

  Game_Temp.prototype.getGeoDataDistance = function() {
    if (this._geoDataLog.address === undefined || this.isGeoDataEmpty()) {
      return -1;
    }
    var lat = this._geoDataLog.lat;
    var lng = this._geoDataLog.lng;
    var lat2 = (this._geoData[0][2][0] - lat) * Math.PI / 180;
    var lng2 = (this._geoData[0][2][1] - lng) * Math.PI / 180;
    lat2 *= earthR;
    lng2 = Math.cos(lat * Math.PI / 180) * earthR * lng2;
    return Math.sqrt(lat2 * lat2 + lng2 * lng2);
  };
  
  //-----------------------------------------------------------------------------
  // Game_Interpreter
  //

  var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
  Game_Interpreter.prototype.pluginCommand = function(command, args) {
    _Game_Interpreter_pluginCommand.call(this, command, args);
    if (command === 'TMGoogleMaps') {
      switch (args[0]) {
      case 'geoCoding':
        var actor = $gameActors.actor(Number(args[1]));
        if (actor) {
          $gameTemp.geoCoding(actor.name());
        }
        break;
      case 'geoParallax':
        var vx = Number(args[1]);
        var vy = Number(args[2]);
        $gameMap.changeParallax('googleMaps' + $gameTemp._geoKeyword,
                                vx !== 0, vy !== 0, vx, vy);
      }
    }
  };
  
  //-----------------------------------------------------------------------------
  // Spriteset_Map
  //

  var _Spriteset_Map_updateParallax = Spriteset_Map.prototype.updateParallax;
  Spriteset_Map.prototype.updateParallax = function() {
    var parallaxName = $gameMap.parallaxName();
    if (this._parallaxName !== parallaxName) {
      this._parallaxName = parallaxName;
      var re = /^googleMaps(.+)$/;
      match = re.exec(this._parallaxName);
      if (match) {
        if ($gameTemp.isGeoDataEmpty()) {
        } else {
          var geoData = $gameTemp.geoData();
          var lat = geoData[0][2][0];
          var lng = geoData[0][2][1];
          url = 'http://maps.google.com/maps/api/staticmap?center=';
          url += lat + ',' + lng + '&zoom=' + mapZoom + '&size=';
          url += mapWidth + 'x' + mapHeight + '&maptype=';
          url += mapType + '&sensor=false&language=ja';
          this._parallax.bitmap = ImageManager.loadGoogleBitmap(url);
          if (this._parallax.bitmap) {
              this._parallax.origin.x = $gameMap.parallaxOx();
              this._parallax.origin.y = $gameMap.parallaxOy();
          }
        }
      }
    }
    _Spriteset_Map_updateParallax.call(this);
  };

  var _Window_Base_convertEscapeCharacters = Window_Base.prototype.convertEscapeCharacters;
  Window_Base.prototype.convertEscapeCharacters = function(text) {
    text = _Window_Base_convertEscapeCharacters.call(this, text);
    text = text.replace(/\x1bDIST/gi, $gameTemp.getGeoDataDistance().toFixed(3) + 'km');
    return text;
  };

})();
