/*
 *  Login.app
 * 
 *  Copyright (c) 1997-2000 Per Liden
 * 
 *  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.
 */

#include <stdio.h>
#include <string.h>
#include "util.h"
#include "preferences.h"
#include "config.h"

static const char* illegalValueMsg(const char* entryName) {
   const char* msg = "illegal value assigned to \"%s\"";
   char*       buffer;

   buffer = alloc(strlen(msg) + strlen(entryName));
   sprintf(buffer, msg, entryName);
   return buffer;
}

static BOOL readString(const proplist_t pl, const char* entryName, char** buffer, const char* defaultValue) {
   proplist_t entry;
   proplist_t key;

   key = PLMakeString((char*)entryName);
   entry = PLGetDictionaryEntry(pl, key);
   PLRelease(key);
   if (!entry) {
      /* Use default if not found */
      *buffer = strdup((char*)defaultValue);
   } else if (!PLIsString(entry)) {
      /* Not a string */
      return NO;
   } else {	
      /* Use proplist value */
      *buffer = strdup(PLGetString(entry));
      PLRelease(entry);
   }

   return YES;
}

static BOOL readStringArray(const proplist_t pl, const char* entryName, char*** buffer, const char* defaultValue) {
   const char* space = " ";
   proplist_t  entry;
   proplist_t  key;
   char*       value;
   char*       tmp1;
   char*       tmp2;
   int         i;
   int         numOfStrings;
    
   key = PLMakeString((char*)entryName);
   entry = PLGetDictionaryEntry(pl, key);
   PLRelease(key);
   if (!entry) {
      /* Use default if not found */
      value = strdup(defaultValue);
   } else if (!PLIsString(entry)) {
      /* Not a string */
      return NO;
   } else {	
      /* Use proplist value */
      value = strdup(PLGetString(entry));
      PLRelease(entry);
   }

   /* Count number of tokens */
   tmp1 = strdup(value);
   tmp2 = strtok(tmp1, space);    
   for (numOfStrings = 0; tmp2 != NULL; numOfStrings++) {
      tmp2 = strtok(NULL, space);
   }
   numOfStrings++;
   free(tmp2);

   /* Insert tokens into array */
   *buffer = alloc(sizeof(char*) * numOfStrings);
   (*buffer)[0] = strtok(value, space);    
   for (i = 1; i < numOfStrings; i++) {
      (*buffer)[i] = strtok(NULL, space);
   }

   return YES;
}

static BOOL readBoolean(const proplist_t pl, const char* entryName, BOOL* buffer, const BOOL defaultValue) {
   proplist_t entry;
   proplist_t key;

   key = PLMakeString((char*)entryName);
   entry = PLGetDictionaryEntry(pl, key);
   PLRelease(key);
   if (!entry) {
      /* Use default if not found */
      *buffer = defaultValue;
   } else if (!PLIsString(entry)) {
      /* Not a string */
      return NO;
   } else {	
      /* Use proplist value */
      *buffer = !strcasecmp(PLGetString(entry), "YES")? YES : NO;
      PLRelease(entry);
   }

   return YES;
}

static BOOL readInteger(const proplist_t pl, const char* entryName, int* buffer, const int defaultValue) {
   proplist_t entry;
   proplist_t key;

   key = PLMakeString((char*)entryName);
   entry = PLGetDictionaryEntry(pl, key);
   PLRelease(key);
   if (!entry) {
      /* Use default if not found */
      *buffer = defaultValue;
   } else if (!PLIsString(entry)) {
      /* Not a string */
      return NO;
   } else {	
      /* Use proplist value */
      sscanf(PLGetString(entry), "%d", buffer);
      PLRelease(entry);
   }

   return YES;
}

static BOOL readPosition(const proplist_t pl, const char* entryName, int** buffer, const int defaultValueX, const int defaultValueY) {
   proplist_t entry;
   proplist_t key;

   key = PLMakeString((char*)entryName);
   entry = PLGetDictionaryEntry(pl, key);
   PLRelease(key);
   if (!entry) {
      /* Use default if not found */
      (*buffer)[0] = defaultValueX;
      (*buffer)[1] = defaultValueY;
   } else if (!PLIsString(entry)) {
      /* Not a string */
      return NO;
   } else {	
      /* Use proplist value */
      sscanf(PLGetString(entry), "%d, %d", (int*)&buffer[0], (int*)&(buffer[1]));
      PLRelease(entry);
   }

   return YES;
}

static BOOL readJustification(const proplist_t pl, const char* entryName, int* buffer, const int defaultValue) {
   proplist_t entry;
   proplist_t key;

   key = PLMakeString((char*)entryName);
   entry = PLGetDictionaryEntry(pl, key);
   PLRelease(key);
   if (!entry) {
      /* Use default if not found */
      *buffer = defaultValue;
   } else if (!PLIsString(entry)) {
      /* Not a string */
      return NO;
   } else {	
      /* Use proplist value */
      char* value = PLGetString(entry);
      if (!strcasecmp(value, "RIGHT")) {
         *buffer = JUSTIFICATION_RIGHT;
      } else if (!strcasecmp(value, "LEFT")) {
         *buffer = JUSTIFICATION_LEFT;
      } else {
         *buffer = JUSTIFICATION_CENTER;
      }
      PLRelease(entry);
   }

   return YES;
}

static const char* readPreferences(const char* file, Preferences* pref) {    
   const char* entryWelcomeMessage = "WelcomeMessage";
   const char* entryRestartMessage = "RestartMessage";
   const char* entryPowerOffMessage = "PowerOffMessage";
   const char* entryXServer = "XServer";
   const char* entryTheme = "Theme";
   const char* entryDisableWelcomeMessage = "DisableWelcomeMessage";
   const char* entryDisableUserShutdown = "DisableUserShutdown";
   const char* entryDisableHostname = "DisableHostname";
   const char* entryDisableAnimations = "DisableAnimations";
   proplist_t  pl;

   /* Read file */
   pl = PLGetProplistWithPath(file);
   if (pl == NULL) {
      return "could not read preferences";
   }

   /* WelcomeMessage */
   if (readString(pl, entryWelcomeMessage, &pref->welcomeMessage, DEFAULT_WELCOMEMESSAGE) == NO) {
      return illegalValueMsg(entryWelcomeMessage);
   }

   /* RestartMessage */
   if (readString(pl, entryRestartMessage, &pref->restartMessage, DEFAULT_RESTARTMESSAGE) == NO) {
      return illegalValueMsg(entryRestartMessage);
   }

   /* PowerOffMessage */
   if (readString(pl, entryPowerOffMessage, &pref->powerOffMessage, DEFAULT_POWEROFFMESSAGE) == NO) {
      return illegalValueMsg(entryPowerOffMessage);
   }

   /* XServer */
   if (readStringArray(pl, entryXServer, &pref->xserver, DEFAULT_XSERVER) == NO) {
      return illegalValueMsg(entryXServer);
   }

   /* Theme */
   if (readString(pl, entryTheme, &pref->theme, DEFAULT_THEME) == NO) {
      return illegalValueMsg(entryTheme);
   }

   /* DisableWelcomeMessage */
   if (readBoolean(pl, entryDisableWelcomeMessage, &pref->disableWelcomeMessage, DEFAULT_DISABLEWELCOMEMESSAGE) == NO) {
      return illegalValueMsg(entryDisableWelcomeMessage);
   }

   /* DisableUserShutdown */
   if (readBoolean(pl, entryDisableUserShutdown, &pref->disableUserShutdown, DEFAULT_DISABLEUSERSHUTDOWN) == NO) {
      return illegalValueMsg(entryDisableUserShutdown);
   }

   /* DisableHostname */
   if (readBoolean(pl, entryDisableHostname, &pref->disableHostname, DEFAULT_DISABLEHOSTNAME) == NO) {
      return illegalValueMsg(entryDisableHostname);
   }

   /* DisableAnimations */
   if (readBoolean(pl, entryDisableAnimations, &pref->disableAnimations, DEFAULT_DISABLEANIMATIONS) == NO) {
      return illegalValueMsg(entryDisableAnimations);
   }

   /* PLRelease(pl); */
   return NULL;
}

static const char* readThemeSettings(const char* file, Preferences* pref) {
   const char* entryPanelImage = "PanelImage";
   const char* entryFieldLabelsImage = "FieldLabelsImage";
   const char* entryPowerButtonUpImage = "PowerButtonUpImage";
   const char* entryPowerButtonDownImage = "PowerButtonDownImage";
   const char* entryRestartButtonUpImage = "RestartButtonUpImage";
   const char* entryRestartButtonDownImage = "RestartButtonDownImage";
   const char* entryAlertIcon = "AlertIcon";
   const char* entryBackgroundColor = "BackgroundColor";
   const char* entryPanelPosition = "PanelPosition";
   const char* entryPowerButtonPosition = "PowerButtonPosition";
   const char* entryRestartButtonPosition = "RestartButtonPosition";
   const char* entryMessagePosition = "MessagePosition";
   const char* entryMessageJustification = "MessageJustification";
   const char* entryMessageColor = "MessageColor";
   const char* entryMessageFont = "MessageFont";
   const char* entryHostnamePosition = "HostnamePosition";
   const char* entryHostnameJustification = "HostnameJustification";
   const char* entryHostnameColor = "HostnameColor";
   const char* entryHostnameFont = "HostnameFont";
   const char* entryInputFont = "InputFont";
   const char* entryInputFontColor = "InputFontColor";
   const char* entryInputCursorHeight = "InputCursorHeight";
   const char* entryInputUserImage = "InputUserImage";
   const char* entryInputUserPosition = "InputUserPosition";
   const char* entryInputPasswordImage = "InputPasswordImage";
   const char* entryInputPasswordPosition = "InputPasswordPosition";
   proplist_t  pl;

   /* Read file */
   pl = PLGetProplistWithPath(file);
   if (pl == NULL) {
      return "could not read theme settings";
   }

   /* PanelImage */
   if (readString(pl, entryPanelImage, &pref->panelImage, DEFAULT_PANELIMAGE) == NO) {
      return illegalValueMsg(entryPanelImage);
   }

   /* FieldLabelsImage */
   if (readString(pl, entryFieldLabelsImage, &pref->fieldLabelsImage, DEFAULT_FIELDLABELSIMAGE) == NO) {
      return illegalValueMsg(entryFieldLabelsImage);
   }

   /* PowerButtonUpImage */
   if (readString(pl, entryPowerButtonUpImage, &pref->powerButtonUpImage, DEFAULT_POWERBUTTONUPIMAGE) == NO) {
      return illegalValueMsg(entryPowerButtonUpImage);
   }

   /* PowerButtonDownImage */
   if (readString(pl, entryPowerButtonDownImage, &pref->powerButtonDownImage, DEFAULT_POWERBUTTONDOWNIMAGE) == NO) {
      return illegalValueMsg(entryPowerButtonDownImage);
   }

   /* RestartButtonUpImage */
   if (readString(pl, entryRestartButtonUpImage, &pref->restartButtonUpImage, DEFAULT_RESTARTBUTTONUPIMAGE) == NO) {
      return illegalValueMsg(entryRestartButtonUpImage);
   }

   /* RestartButtonDownImage */
   if (readString(pl, entryRestartButtonDownImage, &pref->restartButtonDownImage, DEFAULT_RESTARTBUTTONDOWNIMAGE) == NO) {
      return illegalValueMsg(entryRestartButtonDownImage);
   }

   /* AlertIcon */
   if (readString(pl, entryAlertIcon, &pref->alertIcon, DEFAULT_ALERTICON) == NO) {
      return illegalValueMsg(entryAlertIcon);
   }

   /* BackgroundColor */
   if (readString(pl, entryBackgroundColor, &pref->backgroundColor, DEFAULT_BACKGROUNDCOLOR) == NO) {
      return illegalValueMsg(entryBackgroundColor);
   }

   /* PanelPosition */
   if (readPosition(pl, entryPanelPosition, (int**)&pref->panelPosition, DEFAULT_PANELPOSITION_X, DEFAULT_PANELPOSITION_Y) == NO) {
      return illegalValueMsg(entryPanelPosition);
   }

   /* PowerButtonPosition */
   if (readPosition(pl, entryPowerButtonPosition, (int**)&pref->powerButtonPosition, DEFAULT_POWERBUTTONPOSITION_X, DEFAULT_POWERBUTTONPOSITION_Y) == NO) {
      return illegalValueMsg(entryPowerButtonPosition);
   }

   /* RestartButtonPosition */
   if (readPosition(pl, entryRestartButtonPosition, (int**)&pref->restartButtonPosition, DEFAULT_RESTARTBUTTONPOSITION_X, DEFAULT_RESTARTBUTTONPOSITION_Y) == NO) {
      return illegalValueMsg(entryRestartButtonPosition);
   }

   /* MessagePosition */
   if (readPosition(pl, entryMessagePosition, (int**)&pref->messagePosition, DEFAULT_MESSAGEPOSITION_X, DEFAULT_MESSAGEPOSITION_Y) == NO) {
      return illegalValueMsg(entryMessagePosition);
   }

   /* MessageJustification */
   if (readJustification(pl, entryMessageJustification, &pref->messageJustification, DEFAULT_MESSAGEJUSTIFICATION) == NO) {
      return illegalValueMsg(entryMessageJustification);
   }

   /* MessageFont */
   if (readString(pl, entryMessageFont, &pref->messageFont, DEFAULT_MESSAGEFONT) == NO) {
      return illegalValueMsg(entryMessageFont);
   }

   /* MessageColor */
   if (readString(pl, entryMessageColor, &pref->messageColor, DEFAULT_MESSAGECOLOR) == NO) {
      return illegalValueMsg(entryMessageColor);
   }

   /* HostnamePosition */
   if (readPosition(pl, entryHostnamePosition, (int**)&pref->hostnamePosition, DEFAULT_HOSTNAMEPOSITION_X, DEFAULT_HOSTNAMEPOSITION_Y) == NO) {
      return illegalValueMsg(entryHostnamePosition);
   }

   /* HostnameJustification */
   if (readJustification(pl, entryHostnameJustification, &pref->hostnameJustification, DEFAULT_HOSTNAMEJUSTIFICATION) == NO) {
      return illegalValueMsg(entryHostnameJustification);
   }

   /* HostnameFont */
   if (readString(pl, entryHostnameFont, &pref->hostnameFont, DEFAULT_HOSTNAMEFONT) == NO) {
      return illegalValueMsg(entryHostnameFont);
   }

   /* HostnameColor */
   if (readString(pl, entryHostnameColor, &pref->hostnameColor, DEFAULT_HOSTNAMECOLOR) == NO) {
      return illegalValueMsg(entryHostnameColor);
   }

   /* InputFont */
   if (readString(pl, entryInputFont, &pref->inputFont, DEFAULT_INPUTFONT) == NO) {
      return illegalValueMsg(entryInputFont);
   }

   /* InputFontColor */
   if (readString(pl, entryInputFontColor, &pref->inputFontColor, DEFAULT_INPUTFONTCOLOR) == NO) {
      return illegalValueMsg(entryInputFontColor);
   }

   /* InputCursorHeight */
   if (readInteger(pl, entryInputCursorHeight, &pref->inputCursorHeight, DEFAULT_INPUTCURSORHEIGHT) == NO) {
      return illegalValueMsg(entryInputCursorHeight);
   }

   /* InputUserImage */
   if (readString(pl, entryInputUserImage, &pref->inputUserImage, DEFAULT_INPUTUSERIMAGE) == NO) {
      return illegalValueMsg(entryInputUserImage);
   }

   /* InputUserPosition */
   if (readPosition(pl, entryInputUserPosition, (int**)&pref->inputUserPosition, DEFAULT_INPUTUSERPOSITION_X, DEFAULT_INPUTUSERPOSITION_Y) == NO) {
      return illegalValueMsg(entryInputUserPosition);
   }

   /* InputPasswordImage */
   if (readString(pl, entryInputPasswordImage, &pref->inputPasswordImage, DEFAULT_INPUTPASSWORDIMAGE) == NO) {
      return illegalValueMsg(entryInputPasswordImage);
   }

   /* InputPasswordPosition */
   if (readPosition(pl, entryInputPasswordPosition, (int**)&pref->inputPasswordPosition, DEFAULT_INPUTPASSWORDPOSITION_X, DEFAULT_INPUTPASSWORDPOSITION_Y) == NO) {
      return illegalValueMsg(entryInputPasswordPosition);
   }

   /* PLRelease(pl); */
   return NULL;
}

Preferences* readConfiguration(const char* programPath) {
   Preferences* pref;
   char*        path;
   char*        file;
   const char*  errorMsg;
   const char*  errorText = "%s\n\nYou can check your configuration with the \"--checkconfig\" option\nPress ENTER to terminate Login.app\n";

   /* Initialize preferences structure */
   pref = alloc(sizeof(Preferences));

   /* Get program path */
   path = getApplicationPath(programPath);

   /* Read preferences */
   file = stringCombine(path, FILE_PREFERENCES);
   errorMsg = readPreferences(file, pref);
   free(file);

   if (errorMsg != NULL) {    
      printError(errorText, errorMsg);
      getchar();
      exit(1);
   }

   /* Read theme settings */
   file = stringCombine(stringCombine(stringCombine(path, THEME_DIR"/"), pref->theme), "/"FILE_THEME_SETTINGS);
   errorMsg = readThemeSettings(file, pref);
   free(file);
    
   if (errorMsg != NULL) {
      printError(errorText, errorMsg);
      getchar();
      exit(1);
   }

   free(path);
   return pref;
}

void checkConfiguration(const char* programPath) {
   Preferences* pref;
   const char*  yes = "Yes";
   const char*  no = "No";
   const char*  errorMsg;
   char*        path;
   char*        file;

   /* Initialize preferences structure */
   pref = alloc(sizeof(Preferences));

   /* Get program path */
   path = getApplicationPath(programPath);

   /* Read preferences */
   file = stringCombine(path, FILE_PREFERENCES);
   printf("Preferences: (file \"%s\")\n", file);
   errorMsg = readPreferences(file, pref);
   free(file);

   if (errorMsg != NULL) {
      free(path);
      printError("%s\n", errorMsg);
      return;
   } else {
      int i;
      printf("  WelcomeMessage:\t\t\"%s\"\n", pref->welcomeMessage);
      printf("  RestartMessage:\t\t\"%s\"\n", pref->restartMessage);
      printf("  PowerOffMessage:\t\t\"%s\"\n", pref->powerOffMessage);
      printf("  XServer:\t\t\t\"");
      for(i = 0; pref->xserver[i] != NULL; i++) {
         printf("%s", pref->xserver[i]);
         if (pref->xserver[i+1] != NULL) {
            printf(" ");
         }
      }	
      printf("\"\n");
      printf("  Theme:\t\t\t\"%s\"\n", pref->theme);
      printf("  DisableWelcomeMessage:\t%s\n", pref->disableWelcomeMessage == YES ? yes : no);
      printf("  DisableUserShutdown:\t\t%s\n", pref->disableUserShutdown == YES ? yes : no);
      printf("  DisableHostname:\t\t%s\n", pref->disableHostname == YES ? yes : no);
      printf("  DisableAnimations:\t\t%s\n", pref->disableAnimations == YES ? yes : no);
   }

   /* Read theme settings */
   file = stringCombine(stringCombine(stringCombine(path, THEME_DIR"/"), pref->theme), "/"FILE_THEME_SETTINGS);
   printf("\nTheme settings: (file \"%s\")\n", file);
   errorMsg = readThemeSettings(file, pref);
   free(file);
    
   if (errorMsg != NULL) {
      free(path);
      printError("%s\n", errorMsg);
      return;
   } else {
      printf("  PanelImage:\t\t\t\"%s\"\n", pref->panelImage);
      printf("  FieldLabelsImage:\t\t\"%s\"\n", pref->fieldLabelsImage);
      printf("  PowerButtonUpImage:\t\t\"%s\"\n", pref->powerButtonUpImage);
      printf("  PowerButtonDownImage:\t\t\"%s\"\n", pref->powerButtonDownImage);
      printf("  RestartButtonUpImage:\t\t\"%s\"\n", pref->restartButtonUpImage);
      printf("  RestartButtonDownImage:\t\"%s\"\n", pref->restartButtonDownImage);
      printf("  AlertIcon:\t\t\t\"%s\"\n", pref->alertIcon);
      printf("  BackgroundColor:\t\t\"%s\"\n", pref->backgroundColor);
      printf("  PanelPosition:\t\t%d, %d\n", pref->panelPosition[0], pref->panelPosition[1]);
      printf("  PowerButtonPosition:\t\t%d, %d\n", pref->powerButtonPosition[0], pref->powerButtonPosition[1]);
      printf("  RestartButtonPosition:\t%d, %d\n", pref->restartButtonPosition[0], pref->restartButtonPosition[1]);
      printf("  MessagePosition:\t\t%d, %d\n", pref->messagePosition[0], pref->messagePosition[1]);
      printf("  MessageJustification:\t\t");
      if (pref->messageJustification == JUSTIFICATION_LEFT) {
         printf("Left\n");
      } else if (pref->messageJustification == JUSTIFICATION_RIGHT) {
         printf("Right\n");
      } else {
         printf("Center\n");
      }
      printf("  MessageColor:\t\t\t\"%s\"\n", pref->messageColor);
      printf("  MessageFont:\t\t\t\"%s\"\n", pref->messageFont);
      printf("  HostnamePosition:\t\t%d, %d\n", pref->hostnamePosition[0], pref->hostnamePosition[1]);
      printf("  HostnameJustification:\t");
      if (pref->hostnameJustification == JUSTIFICATION_LEFT) {
         printf("Left\n");
      } else if (pref->hostnameJustification == JUSTIFICATION_RIGHT) {
         printf("Right\n");
      } else {
         printf("Center\n");
      }
      printf("  HostnameColor:\t\t\"%s\"\n", pref->hostnameColor);
      printf("  HostnameFont:\t\t\t\"%s\"\n", pref->hostnameFont);
      printf("  InputFont:\t\t\t\"%s\"\n", pref->inputFont);
      printf("  InputFontColor:\t\t\"%s\"\n", pref->inputFontColor);
      printf("  InputCursorHeight:\t\t%d\n", pref->inputCursorHeight);
      printf("  InputUserImage:\t\t%s\n", pref->inputUserImage);
      printf("  InputUserPosition:\t\t%d, %d\n", pref->inputUserPosition[0], pref->inputUserPosition[1]);
      printf("  InputPasswordImage:\t\t%s\n", pref->inputPasswordImage);
      printf("  InputPasswordPosition:\t%d, %d\n", pref->inputPasswordPosition[0], pref->inputPasswordPosition[1]);
   }

   free(path);
   free(pref);
}

