'use strict';

/* This file will be used by server for online game, and by app for local game
Therfore it should not have any dependency on any of those environments. 

It is a state machine that follows the game steps

It receives a dataStore to get and share data but doesn't care what is 
behind (socket.io comm for online, direct call to vuex store for local)
Is gives an interface in order to receive notifications

Receiving interface : 
  - dataStore : provides methods :
    - .load()          : to get saved game data
    - .save(data)      : to store game data and propagate (returns true if it succeeded, false otherwise)
    - .getHeroesJson() : to get JSON file with all heroes cards described 
  
  - messenger (optionnal) :
    - chat(from, message)    : send chat message to the game room

Provides interface :
  - duelControllerProxy : provides methods :
    - endTurn(data) : notifies the controller that players ended current turn with attached data */

import { initHeroesFromJson } from './heroesHelper.js';
import GameStates from './gameStates/gameStates.js';
let DuelController = function (dataStore, messenger = null) {
  let gameData = {
    game: {},
    bluePlayer: {},
    redPlayer: {}
  };
  let allHeroes = null;

  /** ***** STATE MACHINE internal methods ***** */

  // Holds current running state
  let currentGameState = null;

  // Set new current State
  let setCurrentState = stateName => {
    currentGameState = GameStates.createState(stateName, stateCtrl);
    gameData.game.gameState = stateName;
  };

  // get new State
  let getCurrentState = () => {
    return currentGameState;
  };

  // Start the current state
  let startCurrentState = (payload = null) => {
    currentGameState.start(payload);
  };

  // Update the current state
  let updateCurrentState = (payload = null) => {
    currentGameState.update(payload);
  };

  // End the current state
  let endCurrentState = (payload = null) => {
    currentGameState.end(payload);
  };

  let getGameData = () => gameData;

  // Interface to set data and store it
  let storeData = (data = null) => {
    if (data) {
      setData(data);
    }
    return dataStore.save(gameData);
  };

  // Interface to set data only
  let setData = data => {
    gameData = data;
  };

  // Interface to load data
  let loadData = () => {
    gameData = dataStore.load();
  };

  // Interface to get set of all heroes
  let getAllHeroes = () => {
    if (!allHeroes) {
      allHeroes = initHeroesFromJson(dataStore.getHeroesJson());
    }
    return allHeroes;
  };

  // Possibility for Duel Ctrl to chat in online mode
  // In local no need to pass a messenger
  let sendChat = (from, message) => {
    if (messenger) {
      messenger.chat(from, message);
    }
    // If no messenger (in local game), just do nothing
  };

  // Pass those state machine methods to each state
  let stateCtrl = {
    setCurrentState,
    getCurrentState,
    startCurrentState,
    updateCurrentState,
    endCurrentState,
    storeData,
    setData,
    getGameData,
    loadData,
    getAllHeroes,
    sendChat
  };

  /** ***** Following are public methods ***** */

  // Method to create and start a new game (both players are there)
  let startNewGame = function (player1Name, player2Name, gameOptions) {
    // 1st state is init
    setCurrentState('0_INIT');
    //Start it
    startCurrentState({
      player1Name,
      player2Name,
      gameOptions
    });
  };

  // Method to resume existing game, gameData is passed already
  let resumeGame = function (data) {
    gameData = data;
    // Just set state per data in DB
    // This state will wait for update
    setCurrentState(gameData.game.gameState);
  };

  // Provide an interface so that players can notify the DuelController
  let DuelControllerProxy = function() {
    return {
      endTurn: data => {
        currentGameState.update(data);
      }
    };
  };

  // Return public methods
  return {
    startNewGame,
    resumeGame,
    duelControllerProxy: new DuelControllerProxy()
  };
};

export default DuelController;
