text: #include "StdAfx.h"
  #include "stats_submitter.h"
  #include "xrGameSpy/GameSpy_Full.h"
  #include "login_manager.h"
  #include "MainMenu.h"
  #include "profile_store.h"
  #include "awards_store.h"
  #include "best_scores_store.h"
  
  namespace gamespy_profile
  {
  stats_submitter::stats_submitter(CGameSpy_Full* fullgs)
      : m_ltx_file(p_number, q_number, g_number, &stats_submitter::fill_private_key)
  {
      shedule.t_min = 500;
      shedule.t_max = 1000;
      VERIFY(fullgs);
      m_fullgs_obj = fullgs;
      m_atlas_obj = fullgs->GetGameSpyATLAS();
      VERIFY(m_atlas_obj);
      m_last_operation_profile = NULL;
      m_atlas_report = NULL;
      m_last_best_scores = NULL;
      ZeroMemory(m_atlas_connection_id, sizeof(m_atlas_connection_id));
  }
  
  stats_submitter::~stats_submitter() {}
  void stats_submitter::reward_with_award(
      enum_awards_t award_id, u32 const count, gamespy_gp::profile const* profile, store_operation_cb opcb)
  {
      if (!opcb)
      {
          m_last_operation_cb.bind(this, &stats_submitter::onlylog_operation);
      }
      else
      {
          m_last_operation_cb = opcb;
      }
      R_ASSERT(!m_last_operation_profile);
  
      m_last_operation_profile = profile;
      m_report_type = ert_set_award;
      m_last_award_id = award_id;
      m_last_award_count = count;
  
      begin_session();
  }
  
  void stats_submitter::set_best_scores(
      all_best_scores_t const* scores, gamespy_gp::profile const* profile, store_operation_cb opcb)
  {
      if (!opcb)
      {
          m_last_operation_cb.bind(this, &stats_submitter::onlylog_operation);
      }
      else
      {
          m_last_operation_cb = opcb;
      }
      R_ASSERT(!m_last_operation_profile);
  
      m_last_operation_profile = profile;
      m_report_type = ert_set_best_scores;
      m_last_best_scores = scores;
  
      begin_session();
  }
  
  void stats_submitter::submit_all(all_awards_t const* awards, all_best_scores_t const* scores,
      gamespy_gp::profile const* profile, store_operation_cb opcb)
  {
      if (!opcb)
      {
          m_last_operation_cb.bind(this, &stats_submitter::onlylog_operation);
      }
      else
      {
          m_last_operation_cb = opcb;
      }
      R_ASSERT(!m_last_operation_profile);
  
      m_last_operation_profile = profile;
      m_report_type = ert_synchronize_profile;
      m_last_all_awards = awards;
      m_last_best_scores = scores;
  
      begin_session();
  }
  
  void stats_submitter::shedule_Update(u32 dt)
  {
      VERIFY(m_fullgs_obj && m_atlas_obj);
  #ifdef DEBUG
      Msg("--- GameSpy core and atlas thinking ...");
  #endif
      m_fullgs_obj->CoreThink(10); // 10 milliseconds on update
      m_atlas_obj->Think();
  }
  
  void stats_submitter::onlylog_operation(bool const result, char const* err_descr)
  {
      if (!result)
      {
          Msg("! Store operation ERROR: %s", err_descr ? err_descr : "unknown");
          return;
      }
      Msg("* Store operation successfullly complete.");
  }
  
  u32 const stats_submitter::operation_timeout_value = 60000; // 60 seconds
  void stats_submitter::begin_session()
  {
      VERIFY(m_last_operation_profile && m_last_operation_cb);
      SCResult tmp_result = m_atlas_obj->CreateSession(&m_last_operation_profile->mCertificate,
          &m_last_operation_profile->mPrivateData, &stats_submitter::created_session_cb, operation_timeout_value, this);
  
      if (tmp_result != SCResult_NO_ERROR)
      {
          m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(tmp_result).c_str());
          terminate_session();
          return;
      }
  
      Engine.Sheduler.Register(this, FALSE);
  }
  
  void __cdecl stats_submitter::created_session_cb(
      const SCInterfacePtr theInterface, GHTTPResult theHttpResult, SCResult theResult, void* theUserData)
  {
      stats_submitter* my_inst = static_cast<stats_submitter*>(theUserData);
      VERIFY(my_inst && my_inst->m_last_operation_profile);
      if (theHttpResult != GHTTPSuccess)
      {
          my_inst->m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(theHttpResult).c_str());
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
      if (theResult != SCResult_NO_ERROR)
      {
          my_inst->m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(theResult).c_str());
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
      SCResult tmp_result = my_inst->m_atlas_obj->SetReportIntention(NULL, gsi_true,
          &my_inst->m_last_operation_profile->mCertificate, &my_inst->m_last_operation_profile->mPrivateData,
          &stats_submitter::set_intension_cb, stats_submitter::operation_timeout_value, my_inst);
  
      if (tmp_result != SCResult_NO_ERROR)
      {
          my_inst->m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(tmp_result).c_str());
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
  }
  
  void __cdecl stats_submitter::set_intension_cb(
      const SCInterfacePtr theInterface, GHTTPResult theHttpResult, SCResult theResult, void* theUserData)
  {
      stats_submitter* my_inst = static_cast<stats_submitter*>(theUserData);
      VERIFY(my_inst && my_inst->m_last_operation_profile);
      if (theHttpResult != GHTTPSuccess)
      {
          my_inst->m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(theHttpResult).c_str());
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
      if (theResult != SCResult_NO_ERROR)
      {
          my_inst->m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(theResult).c_str());
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
      char const* tmp_connection_id = my_inst->m_atlas_obj->GetConnectionId();
      VERIFY(tmp_connection_id);
      xr_strcpy(static_cast<char*>((void*)my_inst->m_atlas_connection_id), sizeof(my_inst->m_atlas_connection_id),
          tmp_connection_id);
  
      if (!my_inst->prepare_report())
      {
          my_inst->m_last_operation_cb(false, "mp_failed_to_create_report");
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
  
      SCResult tmp_result = my_inst->m_atlas_obj->SubmitReport(my_inst->m_atlas_report, gsi_true,
          &my_inst->m_last_operation_profile->mCertificate, &my_inst->m_last_operation_profile->mPrivateData,
          &stats_submitter::submitted_cb, stats_submitter::operation_timeout_value, my_inst);
      if (tmp_result != SCResult_NO_ERROR)
      {
          my_inst->m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(tmp_result).c_str());
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
  }
  
  void __cdecl stats_submitter::submitted_cb(
      const SCInterfacePtr theInterface, GHTTPResult theHttpResult, SCResult theResult, void* theUserData)
  {
      stats_submitter* my_inst = static_cast<stats_submitter*>(theUserData);
      VERIFY(my_inst && my_inst->m_last_operation_profile);
      if (theHttpResult != GHTTPSuccess)
      {
          my_inst->m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(theHttpResult).c_str());
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
      if (theResult != SCResult_NO_ERROR)
      {
          my_inst->m_last_operation_cb(false, CGameSpy_ATLAS::TryToTranslate(theResult).c_str());
          my_inst->terminate_session();
          Engine.Sheduler.Unregister(my_inst);
          return;
      }
  
      my_inst->m_last_operation_cb(true, "");
      my_inst->terminate_session();
      Engine.Sheduler.Unregister(my_inst);
  }
  
  bool stats_submitter::prepare_report()
  {
      VERIFY(!m_atlas_report);
      SCResult tmp_res = m_atlas_obj->CreateReport(ATLAS_RULE_SET_VERSION, 1, 0, &m_atlas_report);
      VERIFY2((tmp_res == SCResult_NO_ERROR) && (m_atlas_report), "failed to create atlas report");
      if ((tmp_res != SCResult_NO_ERROR) || (!m_atlas_report))
          return false;
  
      tmp_res = m_atlas_obj->ReportBeginGlobalData(m_atlas_report);
      VERIFY2(tmp_res == SCResult_NO_ERROR, "failed to begin global data");
      if (tmp_res != SCResult_NO_ERROR)
          return false;
  
      tmp_res = m_atlas_obj->ReportBeginPlayerData(m_atlas_report);
      VERIFY2(tmp_res == SCResult_NO_ERROR, "failed to begin player data");
      if (tmp_res != SCResult_NO_ERROR)
          return false;
  
      tmp_res = m_atlas_obj->ReportBeginNewPlayer(m_atlas_report);
      VERIFY2(tmp_res == SCResult_NO_ERROR, "failed to begin new player data");
      if (tmp_res != SCResult_NO_ERROR)
          return false;
  
      tmp_res = m_atlas_obj->ReportSetPlayerData(m_atlas_report, 0, m_atlas_connection_id, 0, SCGameResult_NONE,
          m_last_operation_profile->m_profile_id, &m_last_operation_profile->mCertificate);
      VERIFY2(tmp_res == SCResult_NO_ERROR, "failed to set player data");
      if (tmp_res != SCResult_NO_ERROR)
          return false;
  
      bool report_creation_result = false;
      switch (m_report_type)
      {
      case ert_set_award: { report_creation_result = create_award_inc_report();
      }
      break;
      case ert_set_best_scores: { report_creation_result = create_best_scores_report();
      }
      break;
      case ert_synchronize_profile:
      {
          report_creation_result = create_all_awards_report();
          report_creation_result &= create_best_scores_report();
      }
      break;
      default: NODEFAULT;
      }; // switch (m_report_type)
      if (report_creation_result)
      {
          tmp_res = m_atlas_obj->ReportEnd(m_atlas_report, gsi_true, SCGameStatus_COMPLETE);
          VERIFY(tmp_res == SCResult_NO_ERROR);
          return (tmp_res == SCResult_NO_ERROR);
      }
      return false;
  }
  
  bool stats_submitter::add_player_name_to_report()
  {
      SCResult tmp_res =
          m_atlas_obj->ReportAddStringValue(m_atlas_report, KEY_PlayerName, m_last_operation_profile->unique_nick());
      VERIFY(tmp_res == SCResult_NO_ERROR);
      if (tmp_res != SCResult_NO_ERROR)
          return false;
  
      return true;
  }
  
  bool stats_submitter::create_award_inc_report()
  {
  #ifdef XR_PLATFORM_LINUX // FIXME!!
      return false;
  #else
      __time32_t tmp_time = 0;
      _time32(&tmp_time);
  
      SCResult tmp_res = m_atlas_obj->ReportAddIntValue(
          m_atlas_report, get_award_id_key(m_last_award_id), static_cast<gsi_i32>(m_last_award_count));
      VERIFY(tmp_res == SCResult_NO_ERROR);
      if (tmp_res != SCResult_NO_ERROR)
          return false;
  
      tmp_res = m_atlas_obj->ReportAddIntValue(
          m_atlas_report, get_award_reward_date_key(m_last_award_id), static_cast<gsi_i32>(tmp_time));
      VERIFY(tmp_res == SCResult_NO_ERROR);
      if (tmp_res != SCResult_NO_ERROR)
          return false;
  
      return add_player_name_to_report();
  #endif
  }
  
  bool stats_submitter::create_best_scores_report()
  {
      VERIFY(m_last_best_scores);
      SCResult tmp_res;
      for (all_best_scores_t::const_iterator si = m_last_best_scores->begin(), sie = m_last_best_scores->end(); si != sie;
           ++si)
      {
          tmp_res = m_atlas_obj->ReportAddIntValue(m_atlas_report,
              get_best_score_id_key(static_cast<gamespy_profile::enum_best_score_type>(si->first)), si->second);
          VERIFY(tmp_res == SCResult_NO_ERROR);
          if (tmp_res != SCResult_NO_ERROR)
              return false;
      }
      return add_player_name_to_report();
  }
  
  bool stats_submitter::create_all_awards_report()
  {
      VERIFY(m_last_all_awards);
      for (all_awards_t::const_iterator ai = m_last_all_awards->begin(), aie = m_last_all_awards->end(); ai != aie; ++ai)
      {
          SCResult tmp_res = m_atlas_obj->ReportAddIntValue(
              m_atlas_report, get_award_id_key(ai->first), static_cast<gsi_i32>(ai->second.m_count));
          VERIFY(tmp_res == SCResult_NO_ERROR);
          if (tmp_res != SCResult_NO_ERROR)
              return false;
  
          tmp_res = m_atlas_obj->ReportAddIntValue(
              m_atlas_report, get_award_reward_date_key(ai->first), static_cast<gsi_i32>(ai->second.m_last_reward_date));
          VERIFY(tmp_res == SCResult_NO_ERROR);
          if (tmp_res != SCResult_NO_ERROR)
              return false;
      }
      return add_player_name_to_report();
  }
  
  void stats_submitter::terminate_session()
  {
      m_last_operation_cb.clear();
      m_last_operation_profile = NULL;
      m_atlas_report = NULL;
      m_last_best_scores = NULL;
      ZeroMemory(m_atlas_connection_id, sizeof(m_atlas_connection_id));
  }
  
  void stats_submitter::quick_reward_with_award(enum_awards_t award_id, gamespy_gp::profile const* profile)
  {
      profile_store* tmp_prof_store = MainMenu()->GetProfileStore();
      VERIFY(tmp_prof_store);
      awards_store* tmp_awards_store = tmp_prof_store->get_awards_store();
      VERIFY(tmp_awards_store);
  
      all_awards_t& tmp_awards = tmp_awards_store->get_player_awards();
  
      all_awards_t::iterator award_iter = tmp_awards.find(award_id);
      R_ASSERT(award_iter != tmp_awards.end());
      ++award_iter->second.m_count;
  #ifndef XR_PLATFORM_LINUX // FIXME!!!
      __time32_t tmp_time = 0;
      _time32(&tmp_time);
      award_iter->second.m_last_reward_date = static_cast<u32>(tmp_time);
  #endif
      save_file(profile);
  }
  
  void stats_submitter::quick_set_best_scores(all_best_scores_t const* scores, gamespy_gp::profile const* profile)
  {
      VERIFY(scores);
      profile_store* tmp_prof_store = MainMenu()->GetProfileStore();
      VERIFY(tmp_prof_store);
      best_scores_store* tmp_bs_store = tmp_prof_store->get_best_scores_store();
      VERIFY(tmp_bs_store);
  
      all_best_scores_t& tmp_best_scores = tmp_bs_store->get_player_best_scores();
  
      for (all_best_scores_t::iterator i = tmp_best_scores.begin(), ie = tmp_best_scores.end(); i != ie; ++i)
      {
          all_best_scores_t::const_iterator tmp_iter = scores->find(i->first);
          if (tmp_iter == scores->end())
              continue;
          i->second = std::max(i->second, tmp_iter->second);
      }
      save_file(profile);
  }
  
  void stats_submitter::save_file(gamespy_gp::profile const* profile)
  {
      profile_store* tmp_prof_store = MainMenu()->GetProfileStore();
      VERIFY(tmp_prof_store);
      awards_store* tmp_awards_store = tmp_prof_store->get_awards_store();
      VERIFY(tmp_awards_store);
      best_scores_store* tmp_bs_store = tmp_prof_store->get_best_scores_store();
      VERIFY(tmp_prof_store);
  
      all_awards_t& tmp_awards = tmp_awards_store->get_player_awards();
      all_best_scores_t& tmp_best_scores = tmp_bs_store->get_player_best_scores();
  
      CInifile& ltx_to_write = m_ltx_file.get_ltx();
      ltx_to_write.sections().clear();
  
      for (all_awards_t::const_iterator i = tmp_awards.begin(), ie = tmp_awards.end(); i != ie; ++i)
      {
          LPCSTR tmp_award_name = get_award_name(i->first);
          ltx_to_write.w_u16(tmp_award_name, award_count_line, i->second.m_count);
          ltx_to_write.w_u32(tmp_award_name, award_rdate_line, i->second.m_last_reward_date);
      }
  
      for (all_best_scores_t::const_iterator i = tmp_best_scores.begin(), ie = tmp_best_scores.end(); i != ie; ++i)
      {
          LPCSTR tmp_bs_name = get_best_score_name(i->first);
          ltx_to_write.w_u32(tmp_bs_name, best_score_value_line, i->second);
      }
  
  #ifndef XR_PLATFORM_LINUX // FIXME!!!
      __time32_t tmp_time = 0;
      _time32(&tmp_time);
  
      ltx_to_write.w_s32(profile_data_section, profile_id_line, profile->m_profile_id);
      ltx_to_write.w_u32(profile_data_section, profile_last_submit_time, static_cast<u32>(tmp_time));
  #endif
      IWriter* tmp_writer = FS.w_open("$app_data_root$", profile_store_file_name);
      m_ltx_file.sign_and_save(*tmp_writer);
      FS.w_close(tmp_writer);
  }
  
  void stats_submitter::fill_private_key(crypto::xr_dsa::private_key_t& priv_key_dest)
  {
      priv_key_dest.m_value[0] = 0x82;
      priv_key_dest.m_value[1] = 0xf0;
      priv_key_dest.m_value[2] = 0x41;
      priv_key_dest.m_value[3] = 0xe9;
      priv_key_dest.m_value[4] = 0x9a;
      priv_key_dest.m_value[5] = 0x98;
      priv_key_dest.m_value[6] = 0xa0;
      priv_key_dest.m_value[7] = 0xf9;
      priv_key_dest.m_value[8] = 0xff;
      priv_key_dest.m_value[9] = 0xe1;
      priv_key_dest.m_value[10] = 0x14;
      priv_key_dest.m_value[11] = 0x48;
      priv_key_dest.m_value[12] = 0xb3;
      priv_key_dest.m_value[13] = 0xde;
      priv_key_dest.m_value[14] = 0xe3;
      priv_key_dest.m_value[15] = 0x69;
      priv_key_dest.m_value[16] = 0xea;
      priv_key_dest.m_value[17] = 0x16;
      priv_key_dest.m_value[18] = 0x64;
      priv_key_dest.m_value[19] = 0xf2;
  }
  
  } // namespace gamespy_profile
  