/***************************************************************************
 *   Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org>             *
 *   Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr>           *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/
#include "gputils.h"

#include <tqregexp.h>

#include "gputils_compile.h"
#include "gputils_config.h"
#include "devices/pic/pic/pic_memory.h"
#include "common/global/process.h"
#include "gputils_generator.h"

//----------------------------------------------------------------------------
TQString GPUtils::Base::baseExecutable(bool, Tool::OutputExecutableType) const
{
  switch (_category.type()) {
    case Tool::Category::Assembler: return "gpasm";
    case Tool::Category::Linker:    return "gplink";
    case Tool::Category::Librarian: return "gplib";
    default: break;
  }
  return TQString();
}

bool GPUtils::Base::checkExecutableResult(bool withWine, TQStringList &lines) const
{
  return ( lines.count()>0 && lines[0].startsWith(baseExecutable(withWine, Tool::OutputExecutableType::Coff)) );
}

//----------------------------------------------------------------------------
TQString GPUtils::Group::informationText() const
{
  return i18n("<a href=\"%1\">GPUtils</a> is an open-source assembler and linker suite.<br>").arg("http://gputils.sourceforge.net");
}

Tool::Group::BaseData GPUtils::Group::baseFactory(Tool::Category category) const
{
  if ( category==Tool::Category::Assembler ) return BaseData(new ::GPUtils::Base, Both);
  if ( category==Tool::Category::Linker || category==Tool::Category::Librarian ) return BaseData(new ::GPUtils::Base, ProjectOnly);
  return BaseData();
}

PURL::Directory GPUtils::Group::autodetectDirectory(Compile::DirectoryType type, const PURL::Directory &execDir, bool withWine) const
{
  switch (type.type()) {
    case Compile::DirectoryType::LinkerScript: {
      TQString exec = execDir.path() + base(Tool::Category::Linker)->baseExecutable(withWine, Tool::OutputExecutableType::Coff);
      ::Process::StringOutput process;
      process.setup(exec, "-h", withWine);
      if ( ::Process::runSynchronously(process, ::Process::Start, 1000)!=::Process::Exited ) return PURL::Directory();
      TQString s = process.sout() + process.serr();
      TQRegExp re(".*Default linker script path ([^\\n]*)\\n.*");
      if ( !re.exactMatch(s) ) return PURL::Directory();
      return PURL::Directory(re.cap(1));
    }
    case Compile::DirectoryType::Header: {
      TQString exec = execDir.path() + base(Tool::Category::Assembler)->baseExecutable(withWine, Tool::OutputExecutableType::Coff);
      ::Process::StringOutput process;
      process.setup(exec, "-h", withWine);
      if ( ::Process::runSynchronously(process, ::Process::Start, 1000)!=::Process::Exited ) return PURL::Directory();
      TQString s = process.sout() + process.serr();
      TQRegExp re(".*Default header file path ([^\\n]*)\\n.*");
      if ( !re.exactMatch(s) ) return PURL::Directory();
      return PURL::Directory(re.cap(1));
    }
    case Compile::DirectoryType::Executable:
    case Compile::DirectoryType::Library:
    case Compile::DirectoryType::Source:
    case Compile::DirectoryType::Nb_Types: break;
  }
  return PURL::Directory();
}

Compile::Process *GPUtils::Group::processFactory(const Compile::Data &data) const
{
  switch (data.category.type()) {
    case Tool::Category::Assembler:
      if (data.project) return new GPUtils::AssembleProjectFile;
      return new GPUtils::AssembleStandaloneFile;
    case Tool::Category::Linker:
      Q_ASSERT(data.project);
      return new GPUtils::LinkProject;
    case Tool::Category::Librarian:
      Q_ASSERT(data.project);
      return new GPUtils::LibraryProject;
    default: break;
  }
  Q_ASSERT(false);
  return 0;
}

Compile::Config *GPUtils::Group::configFactory(::Project *project) const
{
  return new Config(project);
}

Tool::SourceGenerator *GPUtils::Group::sourceGeneratorFactory() const
{
  return new SourceGenerator;
}
