/***********************************************************************************

    Copyright (C) 2007-2026 Ahmet Öztürk (aoz_2@yahoo.com)

    This file is part of Lifeograph.

    Lifeograph 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 3 of the License, or
    (at your option) any later version.

    Lifeograph 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 Lifeograph.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************************/


#include "settings.hpp"
#include "lifeograph.hpp"
#include "src/helpers.hpp"

#include <fstream>
#include <glib/gstdio.h>    // g_mkdir()


using namespace LoG;


const std::string Settings::s_date_format_orders[ 3 ]  = { "YMD", "DMY", "MDY" };
const std::string Settings::s_date_format_separators   = "./-";

bool
Settings::read()
{
    m_path = Glib::getenv( "LIFEOGRAPH_CONFIG_FILE" );

    if( m_path.empty() )
    {
        m_path = Glib::build_filename( Glib::get_user_config_dir(), "lifeograph", "lifeo.conf" );
    }

    std::ifstream file( PATH( m_path ).c_str() );

    if( ! file.is_open() ) // maiden voyage
    {
        PRINT_DEBUG( "Configuration file does not exist, maiden voyage!" );
        Lifeograph::settings.rtflag_force_welcome = true;
        recentfiles.insert( Glib::filename_to_uri( Lifeograph::EXAMPLEDIARYPATH ) );

        return false;
    }
    else
        Lifeograph::settings.rtflag_force_welcome = false;

    reset();

    std::string line;

    while( getline( file, line ) )
    {
        if( line.size() < 3 )
            continue;

        try
        {
            switch( line[ 0 ] )
            {
                case 'B': // daily backups
                    if( line[ 1 ] != '_' )
                    {
                        if( line.size() > 2 )
                            backup_folder_uri = line.substr( 2 );
                        // update old format:
                        if( line[ 1 ] == 'd' )
                            backup_folder_uri = Glib::filename_to_uri( backup_folder_uri );
                    }
                    break;
                case 'D':
                    if( line[ 1 ] == 'o' )
                        date_format_order = std::stoi( line.substr( 2 ) );
                    else if( line[ 1 ] == 'a' )
                        use_dark_theme = true;
                    else if( line[ 1 ] == '1' )
                        Date::s_week_start_day = std::stoi( line.substr( 4 ) );
                    else
                        date_format_separator = std::stoi( line.substr( 2 ) );
                    break;
                case 'E':
                    // if only a dot (.) no extension will be added automatically
                    diary_extension = line.substr( 2 );
                    if( diary_extension[ 0 ] != '.' )
                        diary_extension.insert( 0, "." );
                    break;
                // TODO: 3.2: position & size settings may go to the diary
                // TODO: 3.2: check if these are within screen boundaries
                case 'H':
                    height = std::stoi( line.substr( 2 ) );
                    break;
                case 'I':
                    idletime = std::stoi( line.substr( 2 ) );
                    if( idletime < 0 || idletime > IDLETIME_MAX )
                        idletime = IDLETIME_DEFAULT;
                    break;
                //case 'L': <- used to denote auto-logout now unused
                case 'N': // python path
                    python_path = line.substr( 2 );
                    print_info( "Extra Python path added = ", python_path );
                    break;
                // case 'O': // special options
                //     if( line.find( "big lists" ) != std::string::npos )
                //         small_lists = false;
                //     break;
                // NOTE: this feature is no longer supported
                case 'P':   // uppercase
                    position_paned_main = STR::get_d( line.substr( 2 ) );
                    // zero width does not make sense:
                    if( position_paned_main == 0 )
                        position_paned_main =  PANEPOS_MAIN_DEFAULT;
                    break;
                case 'p':   // lowercase
                    position_paned_extra = STR::get_d( line.substr( 2 ) );
                    // extra panel position is checked in fix_paned_positions_if_needed()
                    break;
                case 'R':
                    if( line[ 1 ] == 'u' )  // recent file v3000 version (uri)
                        recentfiles.insert( line.substr( 2 ) );
                    else                    // recent file pre-v3000 version (path)
                        recentfiles.insert( Glib::filename_to_uri( line.substr( 2 ) ) );
                    break;
                case 'S':
                    state_maximized = ( line[ 2 ] == 'm' || line[ 2 ] == 'M' );
                    break;
                case 'T':
                    icon_theme = line.substr( 2 );
                    break;
                case 'U':
                    use_imperial_units = ( line[ 2 ] == 'i' || line[ 2 ] == 'I' );
                    break;
                case 'W':
                    width = std::stoi( line.substr( 2 ) );
                    break;
                case 'X':
                    position_x = std::stoi( line.substr( 2 ) );
                    break;
                case 'Y':
                    position_y = std::stoi( line.substr( 2 ) );
                    break;

                case '1': // second tier settings
                    switch( line[ 1 ] )
                    {
                        case 'E':
                            external_text_edit_cmd = line.substr( 3 );
                            break;
                    }
                    break;
                case 0:     // empty line
                case '#':   // comment
                    break;
                default:
                    print_info( "unrecognized option:\n", line );
                    break;
            }
        }
        catch( std::exception& exc )
        {
            print_error( exc.what() );
        }
    }

    update_date_format();

    // update old formats
    if( position_paned_main > 1 ) position_paned_main /= width;
    if( position_paned_extra > 1 ) position_paned_extra /= height;

    file.close();
    return true;
}

bool
Settings::write()
{
    if( access( PATH( m_path ).c_str(), F_OK ) != 0 )
    {
        if( ! Glib::file_test( Glib::path_get_dirname( m_path ), Glib::FileTest::IS_DIR ) )
            g_mkdir_with_parents( Glib::path_get_dirname( m_path ).c_str(), 0700 );
    }

    std::ofstream file( PATH( m_path ).c_str(), std::ios::out | std::ios::trunc );

    if( ! file.is_open() )
    {
        print_error( "Failed to save configuration!" );
        return false;
    }

    file.imbue( std::locale( "C" ) ); // to eliminate thousands separators

    file << "W " << width;
    file << "\nH " << height;
    file << "\nX " << position_x;
    file << "\nY " << position_y;
    file << "\nS " << ( state_maximized ? 'm' : 'u' );
    file << "\nP " << position_paned_main;
    file << "\np " << position_paned_extra;

    // RECENT FILES
    for( const String& path : recentfiles )
        file << "\nRu" << path;

    file << "\nI " << idletime;

    file << "\nDo" << date_format_order;
    file << "\nDs" << date_format_separator;

    file << "\nD1st" << Date::s_week_start_day;

    file << "\nU " << ( use_imperial_units ? 'i' : 'm' );

    if( !backup_folder_uri.empty() )
        file << "\nBy" << backup_folder_uri;

    if( diary_extension != EXTENSION_DEFAULT )
        file << "\nE " << diary_extension;

    if( use_dark_theme )
        file << "\nDark Theme";

    if( ! icon_theme.empty() )
        file << "\nT " << icon_theme;

    // if( small_lists == false )
    //     file << "\nO big lists";
    // NOTE: this feature is no longer supported

    if( !python_path.empty() )
        file << "\nN " << python_path;

    if( !external_text_edit_cmd.empty() )
        file << "\n1E " << external_text_edit_cmd;

    file.close();
    return true;
}

void
Settings::reset()
{
    recentfiles.clear();
    idletime = IDLETIME_DEFAULT;
    date_format_order = 0;
    date_format_separator = 0;
    use_imperial_units = false;
    backup_folder_uri.clear();
    icon_theme.clear();
    diary_extension = EXTENSION_DEFAULT;
    python_path.clear();
}

void
Settings::update_date_format()
{
    Date::s_format_order = s_date_format_orders[ date_format_order ];
    Date::s_format_separator = s_date_format_separators[ date_format_separator ];
}

// maybe later:
//bool
//Settings::get_bool_opt( int i )
//{
//    if( i >= m_bool_opts.size() )
//        throw LoG::Error( "Requested option is out of bounds" );
//    else
//        return m_bool_opts[ i ];
//}
