/* 

                          Firewall Builder

                 Copyright (C) 2000 NetCitadel, LLC

  Author:  Vadim Kurland     vadim@fwbuilder.org

  $Id: Tools.cpp 580 2010-03-09 12:54:25Z rueegsegger $


  This program is free software which we release under the GNU General Public
  License. You may redistribute and/or modify this program under the terms
  of that 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.
 
  To get a copy of the GNU General Public License, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include <fwbuilder/libfwbuilder-config.h>
#include <fwbuilder/Tools.h>
#include <fwbuilder/XMLTools.h>

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

#include <iostream>
#include <sstream>

/*
 * this is workaround, by some reason dirent.h defines DIR as a typedef
 * for struct __dirstream which is not defined anywhere.  07/12/02  vk
 */
#ifndef __dirstream
struct __dirstream {};
#endif

#ifndef _WIN32
#  include <unistd.h>
#  include <dirent.h>
#else
#  include <basetsd.h>
#  include <io.h>
//#  include <windows.h>
#  include <winsock2.h>
#endif


using namespace std;

namespace libfwbuilder
{

char *cxx_strdup(const string &x)
{
    char *res=new char[x.length()+1];
    strcpy(res, x.c_str());
    return res;
}

char *cxx_strdup(const char *x)
{
    if(!x)
        return (char*)NULL;

    char *res=new char[strlen(x)+1];
    strcpy(res,x);
    return res;
}

string substituteMacros(const string &source, const map<string, string> &macros, bool strict) throw(libfwbuilder::FWException)
{
    string name;
    string res;

    enum {
        MODE_TEXT,
        MODE_META,
        MODE_NAME
    } m = MODE_TEXT;
    
    for(size_t i=0;i<source.length();i++)
    {
        char c = source[i];
        switch(m)
        {
        case MODE_TEXT:
            if(c=='$')
                m=MODE_META;
            else
                res+=c;
            break;
        case MODE_META:
            if(c=='$')
            {
                // double '$' means '$'
                res+=c;
            } else
            {
                if(c=='{')
                {
                    m    = MODE_NAME;
                    name = "";
                } else
                {
                    ostringstream err;
                    err << "Unexpected symbol after '$' at postion " << i;
                    throw FWException(err.str());
                }
            }
            break;
        case MODE_NAME:
            if(c=='}')
            {
                map<string, string>::const_iterator i=macros.find(name);
                if(i!=macros.end())
                    res+=(*i).second;
                else if(strict)
                    throw FWException(string("Undefined macro '")+name+"'");
                m = MODE_TEXT;
            } else
                name+=c;
            break;
        }
    }
    
    if(m!=MODE_TEXT)
        throw FWException("Unexpected end of string");

    return res;
}

int  cxx_strcasecmp(const char *s1, const char *s2)
{
#ifndef _WIN32
	return ::strcasecmp(s1,s2);
#else
	return _stricoll(s1,s2);
#endif
}


void init()
{
#ifdef _WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
 
    wVersionRequested = MAKEWORD( 2, 0 );
 
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 )
    {
        // Could not find usable dll
        cerr << "Could not initialize winsock dll v2.0";
        return;
    }
 
    // Confirm that the WinSock DLL supports 2.0.
 
    if ( LOBYTE( wsaData.wVersion ) != 2 ||
         HIBYTE( wsaData.wVersion ) != 0 )
    {
        cerr << "Could not initialize winsock dll v2.0";
        WSACleanup( );
        return; 
    }
#endif

    /* Init XML parser */
    XMLTools::initXMLTools();
   
}

/**
 *  portable function that gets a list of files in the directory.
 *  dir - directory
 *  ext - file extension mask, should be just "xml" rather than "*.xml"
 */
list<string> getDirList(const std::string &dir,
                                      const std::string &ext)
{
    list<string> res;

#ifndef _WIN32
    DIR *d=opendir(dir.c_str());
    if (d!=NULL)
    {
        struct dirent *de;
        while ( (de=readdir(d))!=NULL ) 
        {
            if (strcmp(de->d_name,".")==SAME || strcmp(de->d_name,"..")==SAME)
                continue;

            string pfile=de->d_name;
            string rfile=dir+FS_SEPARATOR+pfile;
            if (rfile.rfind(string(".")+ext)==rfile.size()-ext.size()-1)
                res.push_back(rfile);
        }
    }
    closedir(d);
#else

    struct _finddata_t c_file;
    long hFile;
    string filepath=dir + FS_SEPARATOR + "*." + ext;
    /* Find first file in current directory */
    if( (hFile = _findfirst( filepath.c_str(), &c_file )) != -1L )
    {
        string rfile=dir+FS_SEPARATOR+c_file.name;
        res.push_back(rfile);
        /* Find the rest of the files */
        while( _findnext( hFile, &c_file ) == 0 )
        {
            string rfile=dir+FS_SEPARATOR+c_file.name;
            res.push_back(rfile);
        }
    }
#endif
    return res;
}

unsigned int cxx_sleep(unsigned int seconds)
{
#ifndef _WIN32
        return sleep(seconds);
#else
        Sleep(seconds*1000);
        return 0;
#endif
}

void tokenize(const string& str, vector<string>& tokens, const string& delimiters)
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}

string strip(const string& in, const string& identifier)
{
    string result;
    vector<string> parts;

    tokenize(in, parts, identifier);

    for (vector<string>::iterator it = parts.begin(); it != parts.end(); ++it)
    {
        result += *it;
    }

    return result;
}

string stringify(const vector<string>& parts, const string& delimiter)
{
    string result;

    vector<string>::const_iterator it = parts.begin();

    while (it != parts.end())
    {
        result += *it++;

        if (it != parts.end())
        {
            result += delimiter;
        }
    }

    return result;
}

}
