/***************************************************************************
                          CmdLine.cpp  -  description
                             -------------------
    begin                : Don Jan 29 2004
    copyright            : (C) 2004 by klaus frieler
    email                : kgf@omniversum.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "CmdLine.h"

int CmdLine::findOption(const string& option)
{
   for(int i = 1; i<m_nArgCount; ++i){
      if(string(m_sArgv[i]) == option) return i;      
   }
   return -1;   
}

int CmdLine::findNextOption(const int start)
{
   for(int i = start; i<m_nArgCount; ++i){
      if(m_sArgv[i][0] == '-') return i;
   }
   return -1;
}
const Option* CmdLine::getOptionIdx(const char *option)
{
   string opt(option);
   for(uint i = 0; i<m_nOptCount; ++i){
      string shortOpt = string("-") +  m_Options[i].m_sShortOpt;
      string longOpt = string("--") +  m_Options[i].m_sLongOpt;
      if(opt == shortOpt || opt == longOpt)
         return &m_Options[i];
   }
   return 0;
}


bool  CmdLine::parse()
{
   int end = 0, lastIdx = 1;
   bool bRet = true;
   OptionEntry entry;
   
   for(uint i = 0; i<m_nOptCount; ++i){
      string shortOpt = string("-") +  m_Options[i].m_sShortOpt;
      string longOpt = string("--") +  m_Options[i].m_sLongOpt;
      entry.m_nIndex = m_Options[i].m_nIndex;
      entry.m_nStart = findOption(shortOpt);
      if(entry.m_nStart == -1)
         entry.m_nStart = findOption(longOpt);
      if(entry.m_nStart == -1) continue;
      entry.m_nCount = m_Options[i].m_nParamCount;
      if( entry.m_nCount == -1){
         end  = findNextOption(entry.m_nStart);
         if(end  == -1){
            entry.m_nCount  = m_nArgCount-entry.m_nStart;
         }
         else{
            entry.m_nCount = end - entry.m_nStart -1;
         }               
      }
      if(entry.m_nStart+entry.m_nCount>m_nArgCount){
         bRet = false;
         continue;
      }
      m_OptList.push_back(entry);
      if(entry.m_nStart+entry.m_nCount>=lastIdx){
         lastIdx = entry.m_nStart+entry.m_nCount+1;
      }
   }
   entry.m_nIndex = -1;
   entry.m_nStart = lastIdx-1;
   entry.m_nCount  = m_nArgCount-entry.m_nStart-1;
   if(entry.m_nCount>0){
      m_OptList.push_back(entry);
   }
   else bRet = false;
   return bRet;
}

bool CmdLine::hasOption(const int optIdx) const
{
   for(uint i = 0; i<m_OptList.size(); ++i){
      if(m_OptList[i].m_nIndex == optIdx) return true;
   }
   return false;
}
int CmdLine::getIndex(const int optIdx) const
{
   for(uint i = 0; i<m_OptList.size(); ++i){
      if(m_OptList[i].m_nIndex == optIdx) return i;
   }
   return -1;
}

char *CmdLine::getParam(const int optIdx, const uint paramIdx) const
{
   int idx = getIndex(optIdx);
   if(idx==-1) return 0;

   uint start = m_OptList[idx].m_nStart;
   uint count = m_OptList[idx].m_nCount;
   if(paramIdx>count) return 0;
   return m_sArgv[start+paramIdx+1];
}

bool CmdLine::getFreeParam(const uint paramIdx, string& param) const
{
   char *ptr= getParam(-1, paramIdx);
   param = "";
   if(!ptr) return false;
   param = string(ptr);
   return true;
}

bool CmdLine::getStringParam(const int optIdx,const uint paramIdx, string& param) const
{
   char *ptr = getParam(optIdx, paramIdx);
   param = "";
   if(!ptr) return false;
   param = string(ptr);
   return !param.empty();
}

bool CmdLine::getIntParam(const int optIdx,const uint paramIdx, int& param) const
{
   char *ptr = getParam(optIdx, paramIdx);
   param = 0;
   if(!ptr) return false;
   param = atoi(ptr);
   return true;
}

bool CmdLine::getUIntParam(const int optIdx,const uint paramIdx, uint& param) const
{
   char *ptr = getParam(optIdx, paramIdx);
   param = 0;
   if(!ptr) return false;
   param = (uint)atoi(ptr);
   return true;
}

bool CmdLine::getFloatParam(const int optIdx, const uint paramIdx, double& param) const
{
   char *ptr = getParam(optIdx, paramIdx);
   param = 0;
   if(!ptr) return false;
   param = atof(ptr);
   return true;
}

int CmdLine::getFreeParamCount() const
{
   return getParamCount(-1);
}

int CmdLine::getParamCount(const int optIdx) const
{
   int idx = getIndex(optIdx);
   if(idx == -1) return 0;
   return m_OptList[idx].m_nCount;
   
}
void CmdLine::dumpOptions() const
{
   for(uint i = 0; i<m_OptList.size(); ++i){
      cerr<<"Options "<<i<<" : Id = "<<m_OptList[i].m_nIndex;
      if(m_OptList[i].m_nIndex != -1){
         cerr<<" text: "<<m_sArgv[m_OptList[i].m_nStart];
      }
      else{
         cerr<<" <Frei> ";
      }
      cerr<<" Position: "<<m_OptList[i].m_nStart;
      cerr<<" Params ("<<m_OptList[i].m_nCount<<"): ";
      for(int j = 0; j<m_OptList[i].m_nCount; ++j){
         cerr<<m_sArgv[m_OptList[i].m_nStart+1+j]<<" ";
      }
      cerr<<endl;
   }
}
