package AmphetaDesk::Settings;
###############################################################################
# AmphetaDesk                                           (c) 2000-2002 Disobey #
# morbus@disobey.com                      http://www.disobey.com/amphetadesk/ #
###############################################################################
# ABOUT THIS PACKAGE:                                                         #
#   This package handles AmphetaDesk settings. It both loads and saves the    #
#   settings available, as well as provides an API to access and set the      #
#   various values available. It doesn't need a config file to work - it will #
#   use built-in defaults. Config files are created (and used) when a user    #
#   strays from the norms and tweaks his installation. It stores all the      #
#   settings in a package hash called SETTINGS.                               #
#                                                                             #
# LIST OF ROUTINES BELOW:                                                     #
#   get_setting - get the value of the passed setting name.                   #
#   load_my_settings - reads in the mySettings.xml and returns the data.      #
#   modify_my_settings - examines passed hash and updates settings.           #
#   save_my_settings - saves the relevant configuration to a file.            #
#   set_setting - set the value of the passed setting name.                   #
###############################################################################
#     "forks on your left, knives in the middle, and spoons up your..."       #
###############################################################################

use strict; $|++;
use AmphetaDesk::Utilities;
use File::Spec::Functions;
use XML::Simple;
require Exporter;
use vars qw( @ISA @EXPORT );
@ISA = qw( Exporter );
@EXPORT = qw( get_setting set_setting load_my_settings
              modify_my_settings save_my_settings );

# where are we?
use FindBin qw($Bin);
BEGIN { unshift(@INC, catdir($Bin, "lib")); }

# where we store our
# in-memory settings.
my %SETTINGS;

###############################################################################
# get_setting - get the value of the passed setting name.                     #
# set_setting - set the value of the passed setting name.                     #
###############################################################################
# USAGE:                                                                      #
#    my $answer = get_setting("app_os");                                      #
#    set_setting("app_version", "v6.66");                                     #
#                                                                             #
# NOTES:                                                                      #
#    Returns the value of the passed setting, from $SETTINGS.                 #
#    Sets the passed variable to the passed value, in $SETTINGS               #
#                                                                             #
# RETURNS:                                                                    #
#    $value; the value of the passed or set.                                  #
#    undef; if the setting doesn't exist or isn't defined.                    #
###############################################################################

sub get_setting {
   my ($setting) = @_;
   $SETTINGS{$setting} || undef;
}

sub set_setting {
   my ($setting, $value) = @_;
   $SETTINGS{$setting} = $value;
   $SETTINGS{$setting}; 
}

###############################################################################
# load_my_settings - reads in the mySettings.xml and returns the data.        #
###############################################################################
# USAGE:                                                                      #
#    load_my_settings;                                                        #
#    load_my_settings("/path/to/file");                                       #
#                                                                             #
# NOTES:                                                                      #
#    This routine reads in the passed file into %SETTINGS. If this file       #
#    does not exist, it will create one in memory based on the defaults.      #
#    This fixes an earlier (pre v0.92) problem where upgrading became a       #
#    hassle since the files could be overwritten. If any changes are made     #
#    to the default settings, then they are saved to disk.                    #
#                                                                             #
# RETURNS:                                                                    #
#    die; if any of the important directories do not exist                    #
#    1; if this routine doesn't die, then it returns 1 automatically          #
###############################################################################

sub load_my_settings {

   my ($passed_path) = @_;

   # load if it exists.
   my $temp_settings;
   if ($passed_path and -e $passed_path) {
      $temp_settings = XMLin($passed_path, suppressempty => 1);
   }

   # our default settings. overridden by user config.
   note("User settings configuration exists. Loading them in.") if -e $passed_path;
   note("User settings configuration does not exist. Using defaults.") unless -e $passed_path;
   $SETTINGS{app_version}                     = "0.93.1";
   $SETTINGS{app_url}                         = "http://www.disobey.com/amphetadesk/";
   $SETTINGS{app_copyright}                   = "Copyright 2000-2002 Disobey.com";
   $SETTINGS{app_contact}                     = "Morbus Iff";
   $SETTINGS{app_email}                       = "morbus\@disobey.com";
   $SETTINGS{app_os}                          = $^O;
   $SETTINGS{dir_data}                        = catdir($Bin, "data");
   $SETTINGS{dir_docs}                        = catdir($Bin, "docs");
   $SETTINGS{dir_templates}                   = catdir($Bin, "templates", "default");
   $SETTINGS{dir_gui}                         = catdir($SETTINGS{dir_templates}, "gui");
   $SETTINGS{dir_data_channels}               = catdir($SETTINGS{dir_data}, "channels");
   $SETTINGS{dir_data_lists}                  = catdir($SETTINGS{dir_data}, "lists");
   $SETTINGS{dir_data_internal}               = catdir($SETTINGS{dir_data}, "internal");
   $SETTINGS{names_file_myChannels}           = "myChannels.opml";
   $SETTINGS{names_file_mySettings}           = "mySettings.xml";
   $SETTINGS{names_file_services_channels}    = "services-channels-recent.xml";
   $SETTINGS{names_file_version}              = "version.txt";
   $SETTINGS{names_gui_macos_icon}            = "macos_icon.pict";
   $SETTINGS{names_gui_linux_icon}            = "linux_icon.png";
   $SETTINGS{names_gui_win_icon}              = "win_icon.ico";
   $SETTINGS{names_gui_macos_logo}            = "macos_logo.pict";
   $SETTINGS{names_gui_linux_logo}            = "linux_logo.png";
   $SETTINGS{names_gui_win_logo}              = "win_logo.bmp";
   $SETTINGS{files_gui_macos_icon}            = catfile($SETTINGS{dir_gui}, $SETTINGS{names_gui_macos_icon});
   $SETTINGS{files_gui_macos_logo}            = catfile($SETTINGS{dir_gui}, $SETTINGS{names_gui_macos_logo});
   $SETTINGS{files_gui_linux_icon}            = catfile($SETTINGS{dir_gui}, $SETTINGS{names_gui_linux_icon});
   $SETTINGS{files_gui_linux_logo}            = catfile($SETTINGS{dir_gui}, $SETTINGS{names_gui_linux_logo});
   $SETTINGS{files_gui_win_icon}              = catfile($SETTINGS{dir_gui}, $SETTINGS{names_gui_win_icon});
   $SETTINGS{files_gui_win_logo}              = catfile($SETTINGS{dir_gui}, $SETTINGS{names_gui_win_logo});
   $SETTINGS{files_myChannels}                = catfile($SETTINGS{dir_data}, $SETTINGS{names_file_myChannels});
   $SETTINGS{files_mySettings}                = catfile($SETTINGS{dir_data}, $SETTINGS{names_file_mySettings});
   $SETTINGS{files_services_channels}         = catfile($SETTINGS{dir_data_lists}, $SETTINGS{names_file_services_channels});
   $SETTINGS{files_version}                   = catfile($SETTINGS{dir_data_internal}, $SETTINGS{names_file_version});
   $SETTINGS{urls_port_default}               = 8888;
   $SETTINGS{urls_port_secondary}             = 4888;
   $SETTINGS{urls_port_tertiary}              = 48888;
   $SETTINGS{urls_services_channels}          = "http://www.disobey.com/amphetadesk/lists/services-channels-recent.xml";
   $SETTINGS{urls_version_current}            = "http://www.disobey.com/amphetadesk/version.txt";
   $SETTINGS{user_allow_nonlocal_conn}        = 0;
   $SETTINGS{user_browser_path}               = "default";
   $SETTINGS{user_channels_check_interval}    = 180;
   $SETTINGS{user_http_referer}               = "";
   $SETTINGS{user_link_target}                = "_blank";
   $SETTINGS{user_request_timeout}            = 10;
   $SETTINGS{user_proxy_server}               = "";
   $SETTINGS{user_proxy_username}             = "";
   $SETTINGS{user_proxy_password}             = "";
   $SETTINGS{user_start_radio_webserver}      = "";

   # check to make sure all our directories are there.
   unless (-e $SETTINGS{dir_data}         ) { error("Oof! AmphetaDesk couldn't find the 'data' ($SETTINGS{dir_data}) directory. More than likely, you're missing a bunch of important stuff. Try reinstalling, bucko."); }
   unless (-e $SETTINGS{dir_gui}          ) { error("Oof! AmphetaDesk couldn't find the 'gui' ($SETTINGS{dir_gui}) directory. More than likely, you're missing a bunch of important stuff. Try reinstalling, bucko."); }
   unless (-e $SETTINGS{dir_templates}    ) { error("Oof! AmphetaDesk couldn't find the 'templates' ($SETTINGS{dir_settings}) directory. More than likely, you're missing a bunch of important stuff. Try reinstalling, bucko."); }
   unless (-e $SETTINGS{dir_data_channels}) { mkdir($SETTINGS{dir_data_channels}, 0777); }
   unless (-e $SETTINGS{dir_data_lists}   ) { mkdir($SETTINGS{dir_data_lists},    0777); }
   unless (-e $SETTINGS{dir_data_internal}) { mkdir($SETTINGS{dir_data_internal}, 0777); }

   # based on our OS, check to make sure the logos are available.
   if    ($SETTINGS{app_os} =~ /Win/) { unless (-e $SETTINGS{files_gui_win_logo} ) { error("Oof! AmphetaDesk couldn't find the '$SETTINGS{files_gui_win_logo}' image. More than likely, you're missing a bunch of important stuff. Try reinstalling, bucko."); } }
   elsif ($SETTINGS{app_os} =~ /Mac/) { unless (-e $SETTINGS{files_gui_macos_logo} ) { error("Oof! AmphetaDesk couldn't find the '$SETTINGS{files_gui_macos_logo}' image. More than likely, you're missing a bunch of important stuff. Try reinstalling, bucko."); } }
   else  { unless (-e $SETTINGS{files_gui_linux_logo} ) { error("Oof! AmphetaDesk couldn't find the '$SETTINGS{files_gui_linux_logo}' image. More than likely, you're missing a bunch of important stuff. Try reinstalling, bucko."); } }

   # merge the two hashes into our main SETTINGS global.
   foreach ( keys %{ $temp_settings->{urls} } ) { $SETTINGS{"urls_" . $_} = $temp_settings->{urls}->{$_}; }
   foreach ( keys %{ $temp_settings->{user} } ) { $SETTINGS{"user_" . $_} = $temp_settings->{user}->{$_}; }

   # if there is no config file, create one.
   save_my_settings() unless -e $passed_path;

   return 1;

}

###############################################################################
# modify_my_settings - examines passed hash and updates settings.             #
###############################################################################
# USAGE:                                                                      #
#    modify_my_settings ( $form );                                            #
#                                                                             #
# NOTES:                                                                      #
#    This routine looks in the passed hash for variables that start with      #
#    "user_". If it finds any, it will set the matching setting to the new    #
#    value from the passed hash.                                              #
#                                                                             #
# RETURNS:                                                                    #
#    1; this routine always returns successfully.                             #
###############################################################################

sub modify_my_settings {

   my ($form) = @_;

   # foreach matching user configuration, make the change.
   foreach (grep { substr($_, 0, 4) eq "user" } keys %{$form}) {
      set_setting($_, $form->{$_});
   }

   # and then save 'em.
   save_my_settings();

   return 1;

}

###############################################################################
# save_my_settings - saves the relevant configuration to a file.              #
###############################################################################
# USAGE:                                                                      #
#    save_my_settings;                                                        #
#    save_my_settings("/path/to/file");                                       #
#                                                                             #
# NOTES:                                                                      #
#    This routine merely takes the current %SETTINGS, extracts the config     #
#    information that should be saved, and then dumps it to the user's        #
#    data directory (or the passed file location). It will be read in on      #
#    successive loads.                                                        #
#                                                                             #
# RETURNS:                                                                    #
#    1; if the new settings were saved and activated.                         #
#    0; if we couldn't save the settings to the passed file name.             #
###############################################################################

sub save_my_settings {

   my ($passed_path) = @_;

   # just some happy blurbage for the log file.
   note("Creating a brand new settings file from the current settings.");

   # create an outputtable settings structure.
   my $temp_settings; # used for temporary storage.
   foreach (grep { substr($_, 0, 4) eq "user" } keys %SETTINGS) { $temp_settings->{user}->{ substr($_, 5, 99) } = $SETTINGS{$_}; }
   foreach (grep { substr($_, 0, 10) eq "urls_port_" } keys %SETTINGS) { $temp_settings->{urls}->{ substr($_, 5, 99) } = $SETTINGS{$_}; }
   $temp_settings->{urls}->{services_channels} = $SETTINGS{urls_services_channels};
   $temp_settings->{urls}->{version_current}   = $SETTINGS{urls_version_current};

   # and write out the file.
   eval { XMLout( $temp_settings,
                  noattr => 1,
                  rootname => 'settings',
                  xmldecl => "<?xml version=\"1.0\"?>",
                  outputfile => $passed_path || $SETTINGS{files_mySettings},
                  suppressempty => 1 ) } or return 0;

   # die if there are any errors.
   if ($@) { $@ =~ s/[\r\n\f]//g; note("There was an error saving " . $passed_path || $SETTINGS{names_file_mySettings} . ". Please report the following error to " . get_setting("app_email") . " : $@.", 1); }

   return 1;

}

1;
