
/*
   Game 3D goals
      - solid 30 fps on device, and always 60 fps on PC
      - min 600k vertexes per frame
      - min 200k triangles

   Async loading
      - non-blocking I/O, lists of FDs for http and file requests, think something like QSocketNotifier
      - possibly look at thread pools
 */

/*
   Game should start up in SectionLoading
   Loading will connect to server and update configs which include game flow
 */

/*
  User has a guid generated
  when they run the game, it checks server for configs and uploads tracking data
  as they run the game, tracking data is collected on what they are clicking on. sent with guid to tracking server
  the user's guid helps decide which group they are in for AB testing. guid used when getting config / assets
 */

enum GameSection
{
  SectionLoading,         //  I/O
  SectionMainMenu,        //  UI
  SectionGame,            //  3D
  SectionEndScreen,       //  UI
  SectionVideoAds,        //  Ads intergation
  SectionSettings,        //  UI
  SectionGatcha,          //  3D
  SectionBonuses,         //  ?
  SectionShop,            //  IAP/other?
  SectionHighScores,
  SectionLeaderBoards,    //  may need a list control
  SectionCharacterSelect, //  may need a carasole control
  LastSection
};

template<class T, size_t N>
size_t array_size(T (&)[N]){ return N; }

const char *GameSectionToString(GameSection section)
{
  const char* sectionNames[] = {
    "Loading", "MainMenu", "Game", "EndScreen", "VideoAds", "Settings",
    "Gatch", "Bonuses", "Shop", "HighScores", "LeaderBoards", "CharacterSelect"
  };
  static_assert(array_size(sectionNames)==LastSection-1, "If sections changed, update here!");
  if (section < LastSection)
    return sectionNames[section];
  return "BadSection";
}

GameSection GameSectionFromString(std::string section)
{
  for (int i = 0; i < LastSection; i++)
    if (section == GameSectionToString(i))
      return (GameSection)i;
  return LastSection;
}


// Base class for various game states (ie each game section's implementation should derive from this)
class BaseGameState
{
public:
  BaseGameState() {}
  virtual ~BaseGameState() {}
  virtual void Enter() = 0;
  virtual void Exit() = 0;

  virtual void Update(GameUi::DrawItems &items, float elapsed) {}
};


class LoadingState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class MainMenuState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class GameState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class EndScreenState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class VideoAdsState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class SettingsState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class GatchaState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class BonusesState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class ShopState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class HighScoresState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class LeaderBoardsState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};
class CharacterSelectState : public BaseGameState
{
public:
  void Enter() override;
  void Exit() override;
};



// Think tutorial progression also
struct GameFlowSteps
{
};



BaseGameState* CreateStateFromSection(GameSection section)
{
  switch (section)
  {
    case SectionLoading:        return new LoadingState();
    case SectionMainMenu:       return new MainMenuState(); 
    case SectionGame:           return new GameState(); 
    case SectionEndScreen:      return new EndScreenState(); 
    case SectionVideoAds:       return new VideoAdsState(); 
    case SectionSettings:       return new SettingsState(); 
    case SectionGatcha:         return new GatchaState(); 
    case SectionBonuses:        return new BonusesState(); 
    case SectionShop:           return new ShopState(); 
    case SectionHighScores:     return new HighScoresState();  
    case SectionLeaderBoards:   return new LeaderBoardsState(); 
    case SectionCharacterSelect:return new CharacterSeclectionState(); 
    case LastSection:
    default:
      break;
  }
  return NULL;
}


// Profile?  UserProfile  SaveGame
// Potentially in the 'Session Management' / 'Activity Lifecycle' this is the state to save/restore on pause/resume
// Also there is the SaveGame state to upload/download as part of the players profile
struct SessionState
{
  BaseGameState* m_currentState = nullptr;
  GameSection    m_currentSection;
  uint32_t       m_currentScore;
  uint32_t       m_highestScore;
  uint32_t       m_unlockedCharacters; // Assumes up to 32 character

  void TransitionState(GameSection enterState)
  {
    BaseGameState* newState = CreateStateFromSection(enterState);
    if (newState) {
      if (m_currentState)
        m_currentState->Exit();
      m_currentState = newState;
      m_currentSection = enterState;
      m_currentState->Enter();
    } else if (!m_currentState) {
      m_currentState = new LoadingState();
      m_currentSection = SectionLoading;
      m_currentState->Enter();
    }
  }
};


// make declarative form
//
// game_flow_steps:
//        states
//        transitions
//
// pointcuts:
//        sections
//        transitions
//
// actions:
//        pop()
//        goto(section)
//        push(...)
//
// ui, as json:
//  [
//    { 'type' : 'label',  'x' : 10, 'y' : 30, 'text' : 'High Score' },
//    { 'type' : 'label',  'x' : 10, 'y' : 30, 'text' : 'High Score' },
//    { 'type' : 'label',  'x' : 10, 'y' : 30, 'text' : 'High Score' },
//    { 'type' : 'tool',   'x' : 10, 'y' : 30, 'icon' : '1',          'action' : '...' }
//    { 'type' : 'button', 'x' : 10, 'y' : 30, 'text' : 'High Score', 'action' : '...' }
//  ]
//
//
// goto/redirects useful for popups that direct user to specific section, for push notifications etc
//
//
// game objects:
//       coin
//       characters
//       ?



