//-----------------------------------------------------------
// Copyright Christian Arnault LAL-Orsay CNRS
// arnault@lal.in2p3.fr
// Modified by Grigory Rybkin
// See the complete license in cmt_license.txt "http://www.cecill.info". 
//-----------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "cmt_language.h"
#include "cmt_system.h"
#include "cmt_database.h"
#include "cmt_error.h"

/*----------------------------------------------------------*/
/*                                                          */
/*  Operations on Language                                  */
/*                                                          */
/*----------------------------------------------------------*/

/*----------------------------------------------------------*/
void Language::show (const cmt_string& name)
  /*----------------------------------------------------------*/
{
  Language& language = find (name);

  if (language == null ())
    {
      cmt_string t (name);

      CmtError::set (CmtError::language_not_found, t);
    }
  else
    {
      language.show ();
    }
}

/*----------------------------------------------------------*/
void Language::show_all ()
  /*----------------------------------------------------------*/
{
  static LanguageVector& Languages = languages ();

  int number;

  for (number = 0; number < Languages.size (); number++)
    {
      Language& language = Languages[number];

      language.show ();
    }
}

/*----------------------------------------------------------*/
void Language::show_names ()
  /*----------------------------------------------------------*/
{
  static LanguageVector& Languages = languages ();

  int number;

  for (number = 0; number < Languages.size (); number++)
    {
      Language& language = Languages[number];
      cout << language.m_name << endl;
    }
}

/*----------------------------------------------------------*/
void Language::setup_all_fragments ()
  /*----------------------------------------------------------*/
{
  static LanguageVector& Languages = languages ();

  int language_index;

  if (Languages.size () == 0) return;

  for (language_index = 0;
       language_index < Languages.size ();
       language_index++)
    {
      Language& language = Languages[language_index];

      language.setup_fragments ();
    }
}

/*----------------------------------------------------------*/
Language& Language::find (const cmt_string& name)
  /*----------------------------------------------------------*/
{
  static LanguageVector& Languages = languages ();

  int language_index;

  if (Languages.size () == 0) return (null ());

  for (language_index = 0;
       language_index < Languages.size ();
       language_index++)
    {
      Language& language = Languages[language_index];

      if (language.m_name == name)
        {
          return (language);
        }
    }

  return (null ());
}

/*----------------------------------------------------------*/
Language& Language::find_with_suffix (const cmt_string& suffix)
  /*----------------------------------------------------------*/
{
  static LanguageVector& Languages = languages ();

  int language_index;

  if (Languages.size () == 0) return (null ());

  for (language_index = 0;
       language_index < Languages.size ();
       language_index++)
    {
      Language& language = Languages[language_index];

      for (int suffix_index = 0;
           suffix_index < language.suffixes.size ();
           suffix_index++)
        {
          cmt_string& s = language.suffixes[suffix_index];

          if (s == suffix) return (language);
        }
    }

  return (null ());
}

/*----------------------------------------------------------*/
void Language::action (const CmtSystem::cmt_string_vector& words,
                       Use* use)
//void Language::action (const CmtSystem::cmt_string_vector& words)
  /*----------------------------------------------------------*/
{
  cmt_string name;

  int i = 1;

  name = words[i];
  if (name == "") return;
  i++;

  Language& language = add (name);

  for (;i < words.size (); i++)
    {
      cmt_string& w = words[i];
      if (w == "") break;

      if (w.substr (0, 8) == "-suffix=")
        {
          cmt_string& suffix = language.suffixes.add ();

          suffix.erase (0);
          w.substr (8, suffix);
        }
      else if (w.substr (0, 8) == "-linker=")
        {
          w.substr (8, language.linker);
        }
      else if (w.substr (0, 11) == "-prototypes")
        {
          language.prototypes = true;
        }
      else if (w.substr (0, 22) == "-preprocessor_command=")
        {
          w.substr (22, language.preprocessor_command);
        }
      else if (w.substr (0, 10) == "-fragment=")
        {
          w.substr (10, language.fragment_name);
        }
      else if (w.substr (0, 15) == "-output_suffix=")
        {
          w.substr (15, language.output_suffix);
        }
      else if (w.substr (0, 21) == "-extra_output_suffix=")
        {
          cmt_string& suffix = language.extra_output_suffixes.add ();

          suffix.erase (0);
          w.substr (21, suffix);
        }
      else if (w.substr (0, 22) == "-dependencies_options=")
        {
          w.substr (22, language.m_dependencies_options);
        }
    }
  language.m_use = use;
}

/*----------------------------------------------------------*/
Language& Language::add (const cmt_string& name)
  /*----------------------------------------------------------*/
{
  static LanguageVector& Languages = languages ();

  if (name == "") return (null ());

  {
    Language& language = find (name);
    if (language != null ()) return (language);
  }

  Language& language = Languages.add ();

  language.clear ();
  language.m_name = name;
  language.fragment_name = name;

  return (language);
}


/*----------------------------------------------------------*/
void Language::clear_all ()
  /*----------------------------------------------------------*/
{
  static LanguageVector& Languages = languages ();

  for (int i = 0; i < Languages.size (); i++)
    {
      Language& c = Languages[i];
      c.clear ();
    }
  Languages.clear ();
}

/*----------------------------------------------------------*/
Language::LanguageVector& Language::languages ()
  /*----------------------------------------------------------*/
{
  static Database& db = Database::instance ();
  static LanguageVector& Languages = db.languages ();

  return (Languages);
}

/*----------------------------------------------------------*/
Language& Language::null ()
  /*----------------------------------------------------------*/
{
  static Language null_instance;

  return (null_instance);
}

/*----------------------------------------------------------*/
Language::Language ()
  /*----------------------------------------------------------*/
{
  clear ();
}

/*----------------------------------------------------------*/
Language::~Language ()
  /*----------------------------------------------------------*/
{
}

/*----------------------------------------------------------*/
void Language::clear ()
  /*----------------------------------------------------------*/
{
  m_name = "";
  linker = "none";
  prototypes = false;
  preprocessor_command = "-I";
  fragment_name = "";
  output_suffix = "";
  suffixes.clear ();
  extra_output_suffixes.clear ();
  m_native_dependencies = false;
  m_dependencies_options = "none";
  m_dependencies_options_expanded = "";
  m_native_dependencies_set = false;
  m_use  = 0;
}

/*----------------------------------------------------------*/
void Language::show (PrintMode mode, ostream& out)
//void Language::show ()
  /*----------------------------------------------------------*/
{
  out << "language " << m_name;

  int i;

  for (i = 0; i < (suffixes.size ()); i++)
    {
      cmt_string& suffix = suffixes[i];
      
      out << " -suffix=" << suffix;
    }

  if (linker != "none")
    //  if (linker != "")
    {
      switch (mode)
	{
	case Requirements :
	  out << " -linker=" << CmtSystem::quote (linker, " \t");
	  break;
	default:
	  out << " -linker=" << linker;
	  break;
	}
    }

  if (prototypes)
    {
      out << " -prototypes";
    }

  if (preprocessor_command != "-I")
    {
      out << " -preprocessor_command=";
      switch (mode)
	{
	case Requirements :
	  out << CmtSystem::quote (preprocessor_command, " \t");
	  break;
	default:
	  out << preprocessor_command;
	  break;
	}
    }

  if (fragment_name != m_name)
    {
      out << " -fragment=" << fragment_name;
    }

  if (output_suffix != "")
    {
      out << " -output_suffix=" << output_suffix;
    }

  for (i = 0; i < extra_output_suffixes.size (); i++)
    {
      cmt_string& suffix = extra_output_suffixes[i];
      
      out << " -extra_output_suffix=" << suffix;
    }

  if (m_dependencies_options != "none")
    {
      out << " -dependencies_options=";
      switch (mode)
	{
	case Requirements :
	  out << CmtSystem::quote (dependencies_options_expanded (), " \t");
	  break;
	default:
	  out << m_dependencies_options;
	  break;
	}
    }

  out << endl;
}

/*----------------------------------------------------------*/
void Language::setup_fragments ()
  /*----------------------------------------------------------*/
{
  cmt_string n = fragment_name;

  application.set (n);

  n += "_library";

  library.set (n);
}

/*----------------------------------------------------------*/
bool Language::operator == (const cmt_string& name) const
  /*----------------------------------------------------------*/
{
  if (m_name == name) return (true);
  return (false);
}

/*----------------------------------------------------------*/
bool Language::operator == (const Language& other) const
  /*----------------------------------------------------------*/
{
  if (this == &other) return (true);
  return (false);
}

/*----------------------------------------------------------*/
bool Language::operator != (const Language& other) const
  /*----------------------------------------------------------*/
{
  if (this != &other) return (true);
  return (false);
}

/*----------------------------------------------------------*/
bool Language::native_dependencies ()
  /*----------------------------------------------------------*/
{
  setup_native_dependencies ();
  return m_native_dependencies;
}

/*----------------------------------------------------------*/
const cmt_string& Language::dependencies_options () const
  /*----------------------------------------------------------*/
{
  static cmt_string null_string;

  return m_dependencies_options == "none" ? null_string : m_dependencies_options;
}

/*----------------------------------------------------------*/
void Language::setup_native_dependencies ()
  /*----------------------------------------------------------*/
{
  if (m_native_dependencies_set) return;
  m_native_dependencies_set = true;

  if (m_dependencies_options != "none")
    {
      cmt_string opts (m_dependencies_options);
      Symbol::expand (opts);
      if (opts != "")
	{
	  m_native_dependencies = true;
	}
      else
	{
	  m_native_dependencies = false;
	}
      m_dependencies_options_expanded = opts;
    }
  else
    {
      m_native_dependencies = false;
    }

  return;
}

/*----------------------------------------------------------*/
const cmt_string& Language::dependencies_options_expanded ()
  /*----------------------------------------------------------*/
{
  setup_native_dependencies ();
  return m_dependencies_options_expanded;
}
