// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//
// 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 <string.h>
#include <ctype.h>

#include "Naming.h"
#include "ACFileID.h"
#include "ACModel/Utils.h"
#include "AdviceInfo.h"
#include "AspectInfo.h"

#include "Puma/SysCall.h"

void Naming::bypass_id_class (ostream& out, ACM_Call *jpl) {
  out << "__ID";
  mangle (out, (ACM_Name*)jpl->get_parent ());
  if (jpl->get_lid () >= 0)
    out << "_" << jpl->get_lid ();
}

string Naming::bypass_caller_class (ACM_Class *cls) {
  ostringstream out;
  out << "__BYPASS";
  mangle (out, cls);
  return out.str ();
}

void Naming::access_wrapper (ostream& out, ACM_Access *jpl, unsigned depth, int wrapper_number) {
  out << "__" << jpl->type_str() << "_";

  ACM_Name *parent = get_explicit_parent( *jpl );
  mangle( out, parent );

  if (jpl->get_lid () >= 0)
    out << "_" << jpl->get_lid ();
  out << "_" << depth;
  if(wrapper_number >= 0) {
    out << "_" << wrapper_number;
  }
}

void Naming::exec_inner (ostream& out, ACM_Code *jpl) {
  ACM_Function *func = (ACM_Function*)jpl->get_parent ();
  assert (func && (func->type_val () == JPT_Function));

  out << "__exec_old_";
  if (func->get_kind () == FT_CONSTRUCTOR)
    constr_name (out, func);
  else if (func->get_kind () == FT_DESTRUCTOR ||
      func->get_kind () == FT_VIRTUAL_DESTRUCTOR ||
      func->get_kind () == FT_PURE_VIRTUAL_DESTRUCTOR)
    destr_name (out, func);
  else if (func->get_name ().substr (0, 9) == "operator ") {
    op_name (out, func);
  }
  else
    out << func->get_name ();
}

void Naming::action_wrapper (ostream &out, ACM_Any *loc, unsigned depth) {
  out << "__action_func";
}

void Naming::exec_advice (ostream& out, ACM_Execution *jpl, AdviceInfo *adv) {
  out << "__" << (adv->name ().c_str() + 1);
}

void Naming::call_advice (ostream& out, ACM_Call *jpl, AdviceInfo *adv) {
  out << "__" << (adv->name ().c_str() + 1);
}

void Naming::local_id (ostream& out, ACM_Code *jpl) {
  if (jpl->type_val () & JPT_Access) {
    ACM_Access *jpl_code = (ACM_Access*)jpl;
    if (jpl_code->get_lid () >= 0)
      out << "_" << jpl_code->get_lid();
  }
}

void Naming::tjp_struct(ostream& out, ACM_Code *loc, int depth) {
  out << "TJP_";

  ACM_Name *parent = get_explicit_parent( *loc );
  mangle( out, parent );

  local_id (out, loc);
  out << "_" << depth;
}

void Naming::tjp_instance(ostream& out, ACM_Code *loc) {
  out << "tjp";
}

void Naming::tjp_args_array(ostream& out, ACM_Code *loc) {
  out << "args_";

  ACM_Name *parent = get_explicit_parent( *loc );
  mangle( out, parent );

  local_id (out, loc);
}

void Naming::tjp_argtypes(ostream& out, ACM_Code *loc) {
  out << "argtypes_";

  ACM_Name *parent = get_explicit_parent( *loc );
  mangle( out, parent );

  local_id (out, loc);
}

void Naming::cflow (ostream& out, ACM_Aspect &jpl_aspect, int index) {
  out << "::AC::CFlow<" << signature(jpl_aspect) << "," << index << ">";
}

bool Naming::is_tjp_object (const char *candidate) {
  return strcmp (candidate, "tjp") == 0 ||
    strcmp (candidate, "thisJoinPoint") == 0;
}

void Naming::tjp_typedef (ostream& out, const char *name) {
  out << "__JP_" << name;
}

void Naming::type_check_func (ostream &out, const string &unique_name) {
  out << "__ac_" << unique_name;
}

void Naming::guard (ostream &out, ACFileID unit) {
  out << "__ac_guard_";
  mangle_file (out, unit);
}

void Naming::mangle_file (ostream &out, ACFileID file_id) {
  // TODO: better is unit->absolutePath() but the implementation is strange and
  // has to be changed.
  Puma::Filename name;
  if (Puma::SysCall::canonical (file_id.name ().c_str (), name))
    mangle_file (out, name.name ());
}

void Naming::mangle_file (ostream &out, const char *name) {
  const char *curr = name;
  while (*curr) {
    if (*curr == '_' || isalnum (*curr))
      out << *curr;
    else if (*curr == '/' || *curr == '\\' || *curr == ':' || *curr == '.')
      out << "_";
    else
      out << 'X' << (unsigned int)*(unsigned char*)curr;
    curr++;
  }
  out << "__";
}

