/***************************************************************************
 *   Copyright (C) 2006 by Jens Koehler                                    *
 *   irimi_at_gmx_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.                                   *
 *                                                                         *
 *   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.             *
 ***************************************************************************/


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif


#include <unistd.h>
#include <getopt.h>
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "amarokgateway.h"
#include "commands.h"
#include "debugTracer.h"

using namespace std;

namespace
{
const char *SQL_ALBUM_CACHE="SQL_album.cache";
const char *SQL_GENRE_CACHE="SQL_genre.cache";
const char *SQL_ARTIST_CACHE="SQL_artist.cache";
const char *deffile="vdramgw.conf";

}

void check_optargs(const char *opt);
void show_header();
void show_help();
bool create_defconfig(const char* pathfile);

bool readConfigfile (const char *file,
                     string &user,
                     string &pw,
                     int &port,
                     bool &daemon,
                     bool &nocheck,
                     bool& info);

void start_gateway(const char* user, const char *pw, const char* path, int port, bool nocheck, bool refresh);


int main(int argc, char *argv[])
{
    const char *user=0;
    const char *pw=0;

    int port = VDRAMGW_PORT;
    bool daemon = false;
    bool refresh = false;
    bool nocheck = false;
    bool showinfo=false;

    string strUser="User";
    string strPw="Pw";
    string strDefFile;
    const char *defpath=getenv("HOME");

    if (defpath)
        strDefFile=defpath;
    else
        strDefFile=".";

    string strDefPath=strDefFile+string("/.vdramgw/");
    strDefFile=strDefPath+string(deffile);

    const char *userpath=0;

    if (argc==1) // use default config file
    {
        if (!readConfigfile (strDefFile.c_str(),strUser, strPw,port,daemon,nocheck,showinfo))
        {
            mkdir(strDefPath.c_str(),S_IRWXU | S_IRWXG);
            create_defconfig(strDefFile.c_str());
            if (!readConfigfile (strDefFile.c_str(),strUser, strPw,port,daemon,nocheck,showinfo))
            {
                cerr << "IO error accessing config file \"" << strDefFile.c_str() << "\"" << endl;
                return -1;
            }
        }
        user=strUser.c_str();
        pw=strPw.c_str();
    }
    else // command line parser
    {
        const char * short_options="hndrP:u:p:C:i";
        struct option long_options[] =
            {
                {"help", 0, 0, 'h'
                },
                {"nocheck", 0, 0, 'n' },
                {"daemon", 0, 0, 'd' },
                {"refresh", 0, 0, 'r' },
                {"Port", 1, 0, 'P' },
                {"user", 1, 0, 'u' },
                {"passwd", 1, 0, 'p' },
                {"Configpath", 1, 0, 'C' },
                {"info", 0, 0, 'i' },
                {0, 0, 0, 0}
            };

        int next_opt=0;
        int *option_index=NULL;
        opterr = 0; // reset
        while ((next_opt = ::getopt_long (argc, argv, short_options,long_options, option_index)) != -1)
        {
            //cout << " ** optarg=" << optarg << endl;
            switch (next_opt)
            {
            case ':':
            case '?':
                cerr << "Error, unknown argument \"-" << optopt << "\"." << endl;
                show_help();
                return 1;
            case 'h' :
                show_help();
                return 1;
            case 'd' :
                daemon=true;
                break;
            case 'r' :
                refresh=true;
                break;
            case 'i' :
                showinfo=true;
                break;
            case 'n' :
                nocheck=true;
                break;
            case 'u' :
                check_optargs(optarg);
                user = optarg;
                break;
            case 'p' :
                check_optargs(optarg);
                pw = optarg;
                break;
            case 'C' :
                check_optargs(optarg);
                userpath = optarg;
                break;
            case 'P' :
                char* endptr = 0L;
                check_optargs(optarg);
                port = strtol (optarg, &endptr, 10);

                if ((endptr == 0L) || (*endptr != 0L))
                {
                    cerr << "wrong port:" << optarg << endl;
                    show_help ();
                    return 1;
                }
                break;

            }
        }
    } // command line parser ends

    if (userpath)
    {
        defpath=userpath;
        string strFile=string(userpath)+string(deffile);
        if (!readConfigfile (strFile.c_str(),strUser, strPw,port,daemon,nocheck, showinfo))
        {
            mkdir(userpath,S_IRWXU | S_IRWXG);
            create_defconfig(strFile.c_str());
            if (!readConfigfile (strFile.c_str(),strUser, strPw,port,daemon,nocheck,showinfo))
            {
                cerr << "IO error accessing config file \"" << strFile.c_str() << "\"" << endl;
                return -1;
            }
        }

        user=strUser.c_str();
        pw=strPw.c_str();
    }
    else
    {
      userpath=strDefPath.c_str();
    }

    if (!user || !pw)
    {
        cerr << "Gateway login name and/or passward isn't set" << endl;
        show_help();
        return -1;
    }

    if (showinfo)
        AMAROK_TRACER_LEVEL_THRESHOLD=AMAROK_TRACE_INFO;

    if (daemon)
    {
        int pid = fork();
        if (pid == -1)
        {
            cerr << "cannot start in daemon mode" << endl;
            return -1;
        }
        if (pid == 0)
        { // child
            start_gateway(user,pw,userpath,port,nocheck,refresh);
            return 0;

        }
        else
        { // parent
            cout << "VDRAmarokGateway " << VDRAMGW_VERSION
            << " has started with PID=" << pid << endl;
            return 0; //waitpid(pid, &status, 0);
        }
    }
    else
    {

        start_gateway(user,pw,userpath,port,nocheck,refresh);
        return 0;

    }
}

void check_optargs(const char *opt)
{

    if (strlen (opt) <= 0)
    {
        cerr << "missing argument" << endl;
        show_help ();
        exit (1);
    }
}

void start_gateway(const char* user, const char *pw, const char *path, int port, bool nocheck, bool refresh_cache)
{
    AmarokGateway *gateway = 0;
    string album_cache=string(path)+string(SQL_ALBUM_CACHE);
    string artist_cache=string(path)+string(SQL_ARTIST_CACHE);
    string genre_cache=string(path)+string(SQL_GENRE_CACHE);

    gateway = new AmarokGateway (user,pw,album_cache.c_str(),artist_cache.c_str(),genre_cache.c_str());
    bool ok=false;

    if (!nocheck)
        ok=gateway->checkVersion();
    else
    {
        cout << "** amaroK version check disabled ! **\nYou MUST use amaroK 1.4.x !\n";
        ok=true;
    }

    if (ok)
    {
        bool start=true;

        if (!refresh_cache)
        {
            refresh_cache = gateway->checkCache();
            refresh_cache=!refresh_cache;
        }

        if (refresh_cache)
        {
            cout << "Please wait ! SQL cache has to be refreshed before server is started" << endl;
            start=gateway->updateCache();
        }

        if (start)
        {
            cout << "Starting gateway listening port " << port << endl;
            gateway->runGateway(port,refresh_cache);
            ::sleep(10); // wait 10s due to WAIT_TIME client has disconnected
            cout << "gateway has stopped !" << endl;
        }
        else
            cerr << "update of SQL cache resp. start of gateway has failed !" << endl;

    }
    else
        cerr << "start of gateway has failed !" << endl;


    delete gateway;
    gateway=0;
}

bool readConfigfile (const char* file, string &user, string &pw, int &port,bool &daemon, bool &nocheck, bool &info)
{

    string strLine;

    bool bRet=false;

    ifstream in(file);
    if (!in)
    {
        ;//cerr << "Cannot open config file:" << file << endl;
    }
    else
    {
        unsigned int index=0;
        while(in && getline(in,strLine) && !in.eof())
        {
            switch (strLine[0])
            {
            case 'p':
                if (strLine.find("password=")==0 && strLine.length()>=10)
                {
                    index=strLine.find_first_of("=")+1;
                    pw=strLine.substr(index,strLine.length()-(index));
                    bRet = true;
                }
                else if (strLine.find("port=")==0 && strLine.length()>=6)
                {
                    index=strLine.find_first_of("=")+1;
                    char* endptr = 0L;
                    port=(int)strtol(strLine.substr(index,strLine.length()-(index)).c_str(),&endptr,10);
                    bRet = true;
                    //if ((endptr == 0L) || (*endptr != 0L))
                    //   port=VDRAMGW_PORT;
                }
                break;
            case 'u':
                if (strLine.find("user=")==0 && strLine.length()>=6)
                {
                    index=strLine.find_first_of("=")+1;
                    user=strLine.substr(index,strLine.length()-(index));
                    bRet = true;
                }
                break;
            case 'n':
                if (strLine.find("nocheck=")==0 && strLine.length()>=6)
                {
                    bRet = true;
                    index=strLine.find_first_of("=")+1;
                    if(strLine.substr(index,strLine.length()-(index)).find("true")==0)
                        nocheck=true;
                }
                break;
            case 'd':
                if (strLine.find("daemon=")==0 && strLine.length()>=7)
                {
                    bRet = true;
                    index=strLine.find_first_of("=")+1;
                    if(strLine.substr(index,strLine.length()-(index)).find("enabled")==0)
                        daemon=true;

                }
                break;
            case 'i':
                if (strLine.find("info=")==0 && strLine.length()>=7)
                {
                    bRet = true;
                    index=strLine.find_first_of("=")+1;
                    if(strLine.substr(index,strLine.length()-(index)).find("enabled")==0)
                        info=true;

                }
                break;
            case '\n':
            case '#':
            default:
                break;
            }
        }
    }
    return bRet;

}


bool create_defconfig(const char* pathfile)
{
    ofstream out(pathfile);
    if (!out)
    {
        //cerr << "Could'nt create defconfig file:" << pathfile << endl;
        return false;
    }
    else
    {
        out << "#VDRAmarokGateway configuration file"  << endl;
        out << "# created by version " << VDRAMGW_VERSION << endl << endl;
        out << "user=amarok" << endl;
        out << "password=secret" << endl;
        out << "#default port" << endl;
        out << "#port=8173" << endl;

        out << "#default daemon mode is disabled" << endl;
        out << "#daemon=enabled" << endl;

        out << "#show server info messages default disabled"  << endl;
        out << "#info=enabled"  << endl;

        out.close();

    }

    return true;

}


void show_header()
{
    cout << "VDRAmarokGateway for vdr-amarok plugin by irimi_at_gmx_de" << endl;
    cout << "Version " <<  VDRAMGW_VERSION <<" / "<< __DATE__ << " / " << __TIME__ << endl;
}


void show_help ()
{
    show_header();

    cout <<  "\nusage: vdramgw [-h] [-d] [-n] [-r] [-u 'user' -p 'password'] [-P 'Port'] [-i] [-C 'config path']\n\n"
    << "Options:\n"
    << "-h\t--help\tthis page\n"
    << "-d\t--daemon\tstart in daemon mode\n"
    << "-n\t--nocheck\tignore amaroK version during startup\n"
    << "-r\t--refresh\tcreates new SQL result cache files\n"
    << "-P\t--Port\t\tdefines server port [default=" << VDRAMGW_PORT << "]\n"
    << "-u\t--user\tset the server login username\n"
    << "-p\t--passwd\tset the server login password\n"
    << "-i\t--info\tshow server info messages\n"
    << "-C\t--Configpath\tpath to vdramgw.conf & cache files [default='HOME'/.vdramgw/]\n\n";

}
