//
// $Source: /cvsroot/gambit/gambit/sources/gui/analysis.cc,v $
// $Date: 2006/08/20 17:02:14 $
// $Revision: 1.16 $
//
// DESCRIPTION:
// Declaration of analysis storage classes
//
// This file is part of Gambit
// Copyright (c) 2005, The Gambit Project
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif  // WX_PRECOMP
#include <wx/tokenzr.h>

#include "tinyxml.h"    // for XML parser for Load()


#include "libgambit/libgambit.h"
#include "analysis.h"
#include "gamedoc.h"

using namespace Gambit;



//=========================================================================
//                     class gbtAnalysisProfileList
//=========================================================================

// Use anonymous namespace to make these helpers private
namespace {

class gbtNotNashException : public Exception {
public:
  virtual ~gbtNotNashException() { }

  std::string GetDescription(void) const
  { return "Output line does not contain a Nash equilibrium"; }
};

template <class T> MixedStrategyProfile<T> 
OutputToMixedProfile(gbtGameDocument *p_doc, const wxString &p_text)
{
  MixedStrategyProfile<T> profile(p_doc->GetGame());

  wxStringTokenizer tok(p_text, wxT(","));

  if (tok.GetNextToken() == wxT("NE")) {
    if (tok.CountTokens() == (unsigned int) profile.Length()) {
      for (int i = 1; i <= profile.Length(); i++) {
	profile[i] = ToNumber(std::string((const char *) tok.GetNextToken().mb_str()));
      }
      return profile;
    }
  }

  throw gbtNotNashException();
}

template <class T> MixedBehavProfile<T>
OutputToBehavProfile(gbtGameDocument *p_doc, const wxString &p_text)
{
  MixedBehavProfile<T> profile(p_doc->GetGame());

  wxStringTokenizer tok(p_text, wxT(","));

  if (tok.GetNextToken() == wxT("NE")) {
    if (tok.CountTokens() == (unsigned int) profile.Length()) {
      for (int i = 1; i <= profile.Length(); i++) {
	profile[i] = ToNumber(std::string((const char *) tok.GetNextToken().mb_str()));
      }
      return profile;
    }
  }

  throw gbtNotNashException();
}

}  // end anonymous namespace


template <class T> void
gbtAnalysisProfileList<T>::AddOutput(const wxString &p_output)
{
  try {
    if (m_isBehav) {
      MixedBehavProfile<T> profile(OutputToBehavProfile<T>(m_doc, p_output));
      m_behavProfiles.Append(profile);
      m_mixedProfiles.Append(MixedStrategyProfile<T>(profile));
      m_current = m_behavProfiles.Length();
    }
    else {
      MixedStrategyProfile<T> profile(OutputToMixedProfile<T>(m_doc,
							      p_output));
      m_mixedProfiles.Append(profile);
      if (m_doc->IsTree()) {
	m_behavProfiles.Append(MixedBehavProfile<T>(profile));
      }
      m_current = m_mixedProfiles.Length();
    }
  }
  catch (gbtNotNashException &) { }
}

template <class T>
void gbtAnalysisProfileList<T>::BuildNfg(void)
{
  for (int i = 1; i <= m_behavProfiles.Length(); i++) {
    m_mixedProfiles.Append(MixedStrategyProfile<T>(m_behavProfiles[i]));
  }
}

template <class T>
int gbtAnalysisProfileList<T>::NumProfiles(void) const
{
  if (m_doc->IsTree()) {
    return m_behavProfiles.Length();
  }
  else {
    return m_mixedProfiles.Length();
  }
}

template <class T>
void gbtAnalysisProfileList<T>::Clear(void)
{
  m_behavProfiles = List<MixedBehavProfile<T> >();
  m_mixedProfiles = List<MixedStrategyProfile<T> >();
  m_current = 0;
}

//-------------------------------------------------------------------------
//         gbtAnalysisProfileList: Saving and loading profile lists 
//-------------------------------------------------------------------------

// Use anonymous namespace to make these helpers private
namespace {

template <class T> MixedStrategyProfile<T> 
TextToMixedProfile(gbtGameDocument *p_doc, const wxString &p_text)
{
  MixedStrategyProfile<T> profile(p_doc->GetGame());

  wxStringTokenizer tok(p_text, wxT(","));

  for (int i = 1; i <= profile.Length(); i++) {
    profile[i] = ToNumber(std::string((const char *) tok.GetNextToken().mb_str()));
  }

  return profile;
}

template <class T> MixedBehavProfile<T> 
TextToBehavProfile(gbtGameDocument *p_doc, const wxString &p_text)
{
  MixedBehavProfile<T> profile(p_doc->GetGame());

  wxStringTokenizer tok(p_text, wxT(","));
  for (int i = 1; i <= profile.Length(); i++) {
    profile[i] = ToNumber(std::string((const char *) tok.GetNextToken().mb_str()));
  }

  return profile;
}

} // end anonymous namespace

//
// Load a profile list from XML.  Pass a node pointing to an
// <analysis> entry in the workbook file
//
template <class T>
void gbtAnalysisProfileList<T>::Load(TiXmlNode *p_analysis)
{
  Clear();

  TiXmlNode *description = p_analysis->FirstChild("description");
  if (description) {
    m_description = wxString(description->FirstChild()->Value(),
			     *wxConvCurrent);
  }

  for (TiXmlNode *node = p_analysis->FirstChild("profile"); node;
       node = node->NextSiblingElement()) {
    const char *type = node->ToElement()->Attribute("type");
    if (!strcmp(type, "behav")) {
      MixedBehavProfile<T> profile = 
	TextToBehavProfile<T>(m_doc,
			      wxString(node->FirstChild()->Value(),
				       *wxConvCurrent));
      m_behavProfiles.Append(profile);
      m_isBehav = true;
      m_current = m_behavProfiles.Length();
    }
    else {
      MixedStrategyProfile<T> profile =
	TextToMixedProfile<T>(m_doc,
			      wxString(node->FirstChild()->Value(),
				       *wxConvCurrent));
      m_mixedProfiles.Append(profile);
      m_isBehav = false;
      m_current = m_mixedProfiles.Length();
    }
  }
}

template <class T> std::string
gbtAnalysisProfileList<T>::GetPayoff(int pl, int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  try {
    if (m_doc->IsTree()) {
      return ToText(m_behavProfiles[index].GetPayoff(pl),
		    m_doc->GetStyle().NumDecimals());
    }
    else {
      return ToText(m_mixedProfiles[index].GetPayoff(pl),
		    m_doc->GetStyle().NumDecimals());
    }
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string 
gbtAnalysisProfileList<T>::GetRealizProb(const GameNode &p_node,
					 int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  try {
    return ToText(m_behavProfiles[index].GetRealizProb(p_node),
		  m_doc->GetStyle().NumDecimals());
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string 
gbtAnalysisProfileList<T>::GetBeliefProb(const GameNode &p_node,
					 int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  if (!p_node->GetPlayer()) return "";

  try {
    if (m_behavProfiles[index].GetInfosetProb(p_node->GetInfoset()) > Rational(0)) {
      return ToText(m_behavProfiles[index].GetBeliefProb(p_node),
		    m_doc->GetStyle().NumDecimals());
    }
    else {
      // We don't compute assessments yet!
      return "*";
    }
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string 
gbtAnalysisProfileList<T>::GetNodeValue(const GameNode &p_node,
					int p_player, int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  try {
    return ToText(m_behavProfiles[index].GetNodeValue(p_node)[p_player], 
		  m_doc->GetStyle().NumDecimals());
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string 
gbtAnalysisProfileList<T>::GetInfosetProb(const GameNode &p_node,
					  int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  if (!p_node->GetPlayer()) return "";

  try {
    return ToText(m_behavProfiles[index].GetInfosetProb(p_node->GetInfoset()),
		  m_doc->GetStyle().NumDecimals());
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string 
gbtAnalysisProfileList<T>::GetInfosetValue(const GameNode &p_node,
					   int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  if (!p_node->GetPlayer() || p_node->GetPlayer()->IsChance())  return "";

  try {
    if (m_behavProfiles[index].GetInfosetProb(p_node->GetInfoset()) > Rational(0)) {
      return ToText(m_behavProfiles[index].GetInfosetValue(p_node->GetInfoset()),
		    m_doc->GetStyle().NumDecimals());
    }
    else {
      // In the absence of beliefs, this is not well-defined in general
      return "*";
    }
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string 
gbtAnalysisProfileList<T>::GetActionProb(const GameNode &p_node, int p_act,
					 int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  if (p_node->GetPlayer() && p_node->GetPlayer()->IsChance()) {
    GameInfoset infoset = p_node->GetInfoset();
    return infoset->GetActionProb<std::string>(p_act);
  }

  if (!p_node->GetPlayer())  return "";
  
  try {
    const MixedBehavProfile<T> &profile = m_behavProfiles[index];

    if (!profile.IsDefinedAt(p_node->GetInfoset())) {
      return "*";
    }
  
    return ToText(profile.GetActionProb(p_node->GetInfoset()->GetAction(p_act)),
		  m_doc->GetStyle().NumDecimals());
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string
gbtAnalysisProfileList<T>::GetActionProb(int p_action, int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  try {
    const MixedBehavProfile<T> &profile = m_behavProfiles[index];

    if (!profile.IsDefinedAt(profile.GetGame()->GetAction(p_action)->GetInfoset())) {
      return "*";
    }
    
    return ToText(profile[p_action], m_doc->GetStyle().NumDecimals());
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string 
gbtAnalysisProfileList<T>::GetActionValue(const GameNode &p_node, int p_act,
					  int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  if (!p_node->GetPlayer() || p_node->GetPlayer()->IsChance()) return "";
  
  try {
    if (m_behavProfiles[index].GetInfosetProb(p_node->GetInfoset()) > Rational(0)) {
      return ToText(m_behavProfiles[index].GetActionValue(p_node->GetInfoset()->GetAction(p_act)),
		    m_doc->GetStyle().NumDecimals());
    }
    else  {
      // In the absence of beliefs, this is not well-defined
      return "*";
    }
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string
gbtAnalysisProfileList<T>::GetStrategyProb(int p_strategy, int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  try {
    const MixedStrategyProfile<T> &profile = m_mixedProfiles[index];
    return ToText(profile[p_strategy], m_doc->GetStyle().NumDecimals());
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> std::string
gbtAnalysisProfileList<T>::GetStrategyValue(int p_strategy, int p_index) const
{
  int index = (p_index == -1) ? m_current : p_index;

  try {
    const MixedStrategyProfile<T> &profile = m_mixedProfiles[index];
    GameStrategy strategy = profile.GetGame()->GetStrategy(p_strategy);
    return ToText(profile.GetStrategyValue(strategy),
		  m_doc->GetStyle().NumDecimals());
  }
  catch (IndexException &) {
    return "";
  }
}

template <class T> void 
gbtAnalysisProfileList<T>::Save(std::ostream &p_file) const
{
  p_file << "<analysis type=\"list\">\n";

  p_file << "<description>\n";
  p_file << (const char *) m_description.mb_str() << "\n";
  p_file << "</description>\n";

  if (m_doc->IsTree()) {
    for (int j = 1; j <= NumProfiles(); j++) {
      const MixedBehavProfile<T> &behav = m_behavProfiles[j];
      p_file << "<profile type=\"behav\">\n";
      for (int k = 1; k <= behav.Length(); k++) {
	p_file << behav[k];
	if (k < behav.Length()) {
	  p_file << ",";
	}
	else {
	  p_file << "\n";
	}
      }
      p_file << "</profile>\n";
    }
  }
  else {
    for (int j = 1; j <= NumProfiles(); j++) {
      const MixedStrategyProfile<T> &mixed = m_mixedProfiles[j];
      p_file << "<profile type=\"mixed\">\n";
      for (int k = 1; k <= mixed.Length(); k++) {
	p_file << mixed[k];
	if (k < mixed.Length()) {
	  p_file << ",";
	}
	else {
	  p_file << "\n";
	}
      }
      p_file << "</profile>\n";
    }
  }
  p_file << "</analysis>\n";
}



// Explicit instantiations
template class gbtAnalysisProfileList<double>;
template class gbtAnalysisProfileList<Rational>;


syntax highlighted by Code2HTML, v. 0.9.1