/*
 * FreeTime: Acorn Time Client
 * Configuration file handling code
 *
 *  Joseph Heenan, 1996-8
 * All rights reserved.
 *
 * $Id: config,v 1.2 1999/10/16 14:38:33 joseph Exp $
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "wimplib.h"
#include "swis.h"

#include "defines.h"
#include "config.h"

#include "wimpclib.h"


char config_server[100]    = "ntp.demon.co.uk";
int  config_maxdiff        = 120;
int  config_mindiff        = 10;
int  config_windowdelay    = 15;
int  config_timeout        = 5; /* 5 seconds until we timeout */
int  config_retrydelay     = 5; /* 5 seconds between retries */
int  config_retry          = 2; /* two retries */
int  config_setdst         = 1; /* default to setting dst */
int  config_windowdisplay  = WINDOW_SHOWERROR | WINDOW_SHOWSET | WINDOW_SHOWMIN | WINDOW_SHOWOUT;


static const char config_file[] = TASK_DIR ".config";

typedef enum
{
  conf_boolean,
  conf_string,
  conf_integer,
  conf_windowdisplay
} conf_type;

typedef struct
{
  const char  *tag;
  void        *var;
  conf_type   type;
  int         size;
} config_file_tags;

static config_file_tags config_filetags[] = {
  { "Server",                 config_server,             conf_string,        sizeof config_server },
  { "MaxDiff",                &config_maxdiff,           conf_integer,       0                    },
  { "MinDiff",                &config_mindiff,           conf_integer,       0                    },
  { "Display",                &config_windowdelay,       conf_integer,       0                    },
  { "Timeout",                &config_timeout,           conf_integer,       0                    },
  { "ReTryDelay",             &config_retrydelay,        conf_integer,       0                    },
  { "ReTry",                  &config_retry,             conf_integer,       0                    },
  { "SetDST",                 &config_setdst,            conf_boolean,       0                    },
  { "Window",                 &config_windowdisplay,     conf_windowdisplay, 0                    },
  { NULL,                     NULL,                      conf_boolean,       0                    },
};

static int my_strcasecmp(const char *s, const char *t)
{
  int a,b,c;
  for ( ; (a=tolower(*s)) == (b=tolower(c=*t)); t++,s++ )
    if (c==0)
      break;
  return a - b;
}

static void config_processtag( const char *tagname, const char *val )
{
  config_file_tags *tag = config_filetags;

  /* Search through tab table */
  while ( tag->tag && my_strcasecmp( tag->tag, tagname ) != 0 ) tag++;

  if ( !tag->tag )
  {
    char error[100];
    strcpy( error, "Error reading config, tag unknown (\"" );
    strncat( error, tagname, sizeof(error) - strlen(tagname) - 1 - 2 );
    strcat( error, "\")" );
    E_REPORT( error );
    return;
  }

  switch ( tag->type )
  {
    case conf_boolean:
      switch ( tolower(*val) )
      {
        case 'y': *(int *)tag->var = 1; break;
        case 'n': *(int *)tag->var = 0; break;
        default:
        {
          char error[128];
          strcpy( error, "Error reading config, tag value non-boolean, skipped (\"" );
          strncat( error, tagname, sizeof(error) - strlen(tagname) - 1 - 2 );
          strcat( error, "\")" );
          E_REPORT( error );
        }
      }
      break;

    case conf_string:
    {
      int len = strlen(val) + 1;
      if ( len > tag->size )
      {
        char error[128];
        strcpy( error, "Error reading config, tag value exceeds maximum length, truncated (\"" );
        strncat( error, tagname, sizeof(error) - strlen(tagname) - 1 - 2 );
        strcat( error, "\")" );
        E_REPORT( error );
        *(char *)tag->var = 0;
        strncat( tag->var, val, tag->size - 1 );
      }
      else
      {
        memcpy( tag->var, val, len );
      }
      break;
    }

    case conf_integer:
      if ( !isdigit( *val ) )
      {
        char error[128];
        strcpy( error, "Error reading config, tag value non-integer, skipped (\"" );
        strncat( error, tagname, sizeof(error) - strlen(tagname) - 1 - 2 );
        strcat( error, "\")" );
        E_REPORT( error );
        break;
      }
      *(int *)tag->var = atoi( val );
      break;

    case conf_windowdisplay:
      *(int *)tag->var = 0;
      if ( strstr( val, "transfer" ) )  *(int *)tag->var |= WINDOW_SHOWTRANSFER;
      if ( strstr( val, "error" ) )     *(int *)tag->var |= WINDOW_SHOWERROR;
      if ( strstr( val, "set" ) )       *(int *)tag->var |= WINDOW_SHOWSET;
      if ( strstr( val, "min" ) )       *(int *)tag->var |= WINDOW_SHOWMIN;
      if ( strstr( val, "out" ) )       *(int *)tag->var |= WINDOW_SHOWOUT;
      break;
  }
}

static int file_exists( const char *name )
{
  int type;

  if (_swix(OS_File, _INR(0,1) | _OUT(0), 17, name, &type)) return 0;

  if (type == 1) return 1; /* it's a file */

  return 0;
}

int config_load( void )
{
  FILE *f = fopen( config_file, "r" );
  int overlong;
  char line[1024];

  if ( !f )
  {
    if ( !file_exists( config_file ) )
    {
      _swix(OS_CLI, _IN(0), "Filer_Run <FreeTime$Dir>.!FTsetup" );
      exit( EXIT_SUCCESS );
    }
    else
    {
      E_RETURN( -1, "Could not open config file!" );
    }
  }

  overlong = 0;
  while ( fgets( line, sizeof line, f ) )
  {
    char *ptr = line + strlen(line) - 1;
    if ( *ptr != '\n' ) { overlong = 1; continue; }
    if ( overlong )
    {
      overlong = 0;
      E_REPORT("Overlong line found reading config - ignored");
      continue;
    }
    if ( *line == '#' || !*line || *line == '\n' ) continue; /* skip comments, null line and blank lines */
    *ptr = 0;

    ptr = strchr( line, ':' );
    if ( !ptr )
    {
      char error[100];
      strcpy( error, "Error reading config, no ':' in \"" );
      strncat( error, line, sizeof(error) - strlen(line) - 1 - 1 );
      strcat( error, "\"" );
      E_REPORT( error );
      continue;
    }
    *ptr = 0;
    while ( isspace( *++ptr ) );
    config_processtag( line, ptr );
  }
  fclose(f);
  return 0;
}


void config_parsecmdline( int argc, char *argv[] )
{
  int c = 0;

  while ( ++c < argc )
  {
    if ( *argv[c] != '-' || c + 1 >= argc)
    {
      char error[100];
      strcpy( error, "Error parsing command line, invalid tag \"" );
      strncat( error, argv[c], sizeof(error) - strlen(argv[c]) - 1 - 1 );
      strcat( error, "\"" );
      E_REPORT( error );
      continue;
    }

    config_processtag( argv[c] + 1, argv[c+1] );
    c++; /* skip the tag value */
  }
}
