/******************************************************************************
 *      "Copyright (C) 2006, ApS s.r.o Brno, All Rights Reserved"             *
 ******************************************************************************
 *============================================================================*
 *   Version „number“    Header/source file for the project   "file name"     *
 *----------------------------------------------------------------------------*
 * VERSION   DATE    TIME  BY   CHANGE/COMMENTS                               *
 *----------------------------------------------------------------------------*
 *============================================================================*/

//  contains implementation of some auxiliary functions
//
//  author:  Libor Vasicek, xvasic15@stud.fit.vutbr.cz
//  created: 22.02.2006
//
//////////////////////////////////////////////////////////////////////

#ifndef __UTILS_H__
#define __UTILS_H__

#include <iostream>
#include <fstream>
#include <string>

#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))

namespace ObjectFile
{
    ///////////////////////////////////////////////////////////////////////////

    //! Vstupni proud.
    /*! Vyuziva se k postupnemu cteni jednotlivych radku vystupniho formatu.
        Zajistuje i odstraneni komentaru ze zdroje.
    */
    class CInputStream
    {
    public:
        //! Vytvori vstupni proud.
        /*! \param cDelim nastaveni oddelovace konce radku.
        */
        CInputStream(char cDelim = '\n');
        
        //! Vytvori vstupni proud.
        /*! Pri vytvoreni vstupniho proudu je zaroven otevren soubor pro
            cteni. Pokud se soubor nepodari otevrit, je vyvolana vyjimka.
            \param sPath cesta ke vstupnimu souboru.
            \param cDelim nastaveni oddelovace konce radku.
            \sa OpenFile()
        */
        CInputStream(const std::string & sPath, char cDelim = '\n');
        ~CInputStream();

    public:
        //! Otevre vstupni soubor.
        /*! Pokud se soubor nepodari otevrit, je vyvolana vyjimka.
            \param sPath cesta ke vstupnimu souboru.
        */
        void OpenFile(const std::string & sPath);

        //! Uzavre vstupni soubor.
        void CloseFile();

        //! Konec souboru.
        bool Eof();

        //! Vrati jeden radek.
        /*! Pokud se na radku nachazi komentar je odstranen.
        */
        std::string GetLine();

        //! Vrati jeden radek o maximalni delce.
        /*! Pokud na radku existuji dalsi znaky jsou zahozeny a radek
            je precten az do jeho konce.
            \param nFirst n prvnich znaku z aktualniho radku.
        */
        std::string GetLine(int nFirst);

        //! Aktualni radek v souboru.
        inline int CurLine()
        {
            return m_line;
        }

        //! Predchozi radek v souboru.
        inline int PrevLine()
        {
            return m_line - 1;
        }

    private:
        std::ifstream   m_file;
        int             m_line;
        char            m_delim;
    };

    ///////////////////////////////////////////////////////////////////////////

    //! Vystupni proud.
    /*! Vyuziva se k ukladani jednotlivych radku do vystupniho formatu.
    */
    class COutputStream
    {
    public:
        //! Vytvori vystupni proud.
        /*! \param cDelim nastaveni oddelovace konce radku.
        */
        COutputStream(char cDelim = '\n');

        //! Vytvori vystupni proud.
        /*! Pri vytvoreni vystupniho proudu je zaroven otevren soubor pro
            zapis. Pokud se soubor nepodari otevrit, je vyvolana vyjimka.
            \param sPath cesta k vystupnimu souboru.
            \param cDelim nastaveni oddelovace konce radku.
            \sa OpenFile()
        */
        COutputStream(const std::string & sPath, char cDelim = '\n');
        ~COutputStream();

    public:
        //! Otevre vystupni soubor.
        /*! Pokud se soubor nepodari otevrit, je vyvolana vyjimka.
            \param sPath cesta k vystupnimu souboru.
        */
        void OpenFile(const std::string & sPath);

        //! Uzavre vystupni soubor.
        void CloseFile();

        //! Zapise jeden radek do souboru.
        /*! Vstupni retezec je zapsan do souboru a oddelen nastavenym znakem
            pro konec radku.
            \param sLine vstupni retezec bez znaku konce radku.
        */
        void WriteLine(const std::string & sLine = "");

        //! Aktualni radek v souboru.
        inline int CurLine()
        {
            return m_line;
        }

    private:
        std::ofstream   m_file;
        int             m_line;
        char            m_delim;
    };

    ///////////////////////////////////////////////////////////////////////////

    //! Zapouzdruje cele cislo.
    /*! Umoznuje konverze retezce na cele cislo a naopak.
    */
    class Int
    {
    public:
        //! Inicializuje celym cislem.
        Int(int i)
        {
            m_nValue = i;
        }

        //! Inicializuje retezcem.
        /*! V retezci musi byt cislo ve spravnem formatu. Pokud je tento
            format spatny, je vyvolana vyjimka.
        */
        Int(const std::string & s)
        {
            m_nValue = Parse(s);
        }

        //! Vraci aktualni hodnotu cisla.
        inline int Value()
        {
            return m_nValue;
        }

        //! Vraci dekadicke cislo v podobe retezce.
        inline std::string ToString()
        {
            return ToString(m_nValue);
        }

        //! Konverze retezce na cislo.
        /*! \param s vstupni retezec.
            \param base zaklad cisla.
            \return vraci prevedeny retezec na cislo.
                Pokud nastala chyba je vyvolana vyjimka.
        */
        static int Parse(const std::string & s, int base = 10);

        //! Konverze cisla na retezec.
        /*! \param i vstupni cislo.
            \param base zaklad cisla.
            \param digits minimalni pocet cislic.
            \return vraci prevedene cislo na retezec.
                Pokud nastala chyba je vyvolana vyjimka.
        */
        static std::string ToString(int i, int base = 10, int digits = 0);

        static std::string ToString(unsigned i, int base = 10, int digits = 0);

    protected:
        int m_nValue;
    };

    ///////////////////////////////////////////////////////////////////////////

    //! Zapouzdruje praci s casem.
    /*! Umoznuje uchovavat casove udaje a konvertuje retezec na vnitrni format
        a naopak.
    */
    class CTimeStamp
    {
    public:
        //! Standardni konstruktor.
        CTimeStamp()
        {
            m_time = -1;
        }

        //! Inicializace casovym formatem tm.
        CTimeStamp(tm t);

        //! Inicializace casovym formatem time_t.
        CTimeStamp(time_t t)
        {
            m_time = t;
        }

        //! Inicializuje retezcem.
        /*! V retezci musi byt casovy udaj ve formatu YYYY.MM.DD:HH:MM:SS.
            Pokud je tento format chybny, je vyvolana vyjimka.
        */
        CTimeStamp(const std::string & s)
        {
            m_time = Parse(s);
        }

        //! Nastavi objekt na aktualni cas.
        CTimeStamp & SetTime();

        //! Vraci aktualni cas ulozeny v objektu.
        inline time_t Value()
        {
            return m_time;
        }

        //! Vraci aktualni cas ulozeny v objektu v podobe retezce.
        inline std::string ToString()
        {
            return ToString(m_time);
        }

        //! Konverze retezce na cas ve formatu time_t.
        /*! \param s vstupni retezec.
            \return vraci prevedeny retezec na cas.
                Pokud nastala chyba je vyvolana vyjimka.
        */
        static time_t Parse(const std::string & s);

        //! Konverze cisla na retezec.
        /*! \param t vstupni cas ve formatu time_t.
            \return vraci prevedeny cas na retezec.
                Pokud nastala chyba je vyvolana vyjimka.
        */
        static std::string ToString(time_t t);

    protected:
        time_t  m_time;
    };
}

#endif //__UTILS_H__
