/*
  Copyright (c) 2003-2006, Robert F. Beeger (robert at beeger dot net)
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification,
  are permitted provided that the following conditions are met:

      * Redistributions of source code must retain the above copyright notice, this list
        of conditions and the following disclaimer.
      * Redistributions in binary form must reproduce the above copyright notice, this
        list of conditions and the following disclaimer in the documentation and/or other
        materials provided with the distribution.
      * Neither the name of 'Robert F. Beeger' nor the names of his contributors may be
        used to endorse or promote products derived from this software without specific
        prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  Visit http://squareness.beeger.net/ for new releases of Squareness Look And Feel and other
  skins from the Squareness series.
*/
package net.beeger.squareness.theme;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import javax.swing.plaf.ColorUIResource;

/**
 * <p>This SquarenessTheme implementation can be configured from some sort of property bundle -
 * be it a resource bundle, a properties object or a properties file.</p>
 * <p>A file matching the original Squareness theme would look like this:</p>
 * <pre>
 * <code>
 *
 * themeName                            = Original
 * desktopColor                         = 234, 216, 164
 * windowBackgroundColor                = 247,242,225
 * inactiveWindowBorderColor            = 184,175,119
 * normalBorderColor                    = 34, 57, 73
 * disabledBorderColor                  = 134, 144, 150
 * defaultButtonBorderColor             = 170,59,34
 * normalControlBackgroundColor         = 219,196,99
 * selectedControlBackgroundColor       = 211, 211, 42
 * selectedControlBackgroundShadowColor = 163,159,28
 * progressBarBackgroundColor           = 245,246,220
 * pressedScrollBarTrackBackgroundColor = 237,225,185
 * textInputBackgroundColor             = 255,255,255
 * textColor                            = 0,0,0
 * </code>
 * </pre>
 * <p><strong>Note:</strong> The colors are defined in RGB format r,g,b where r, g and b
 * define the red, green and blue components of the color. Each of those
 * must be in the range from 0 to 255. </p>
 */
public class PropertiesSquarenessTheme extends SquarenessTheme
{
  public PropertiesSquarenessTheme (File propertiesFile) throws LoadException
  {
    Properties properties = new Properties();
    try
    {
      properties.load(new FileInputStream(propertiesFile));
      processProperties(properties);
      if (_themeName == null)
      {
        _themeName = propertiesFile.getName();
        if (_themeName.indexOf('.') > -1)
        {
          _themeName = _themeName.substring(0, _themeName.indexOf('.'));
        }
      }
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
  }

  public PropertiesSquarenessTheme (Properties properties) throws LoadException
  {
    processProperties(properties);
  }

  public PropertiesSquarenessTheme(ResourceBundle resourceBundle) throws LoadException
  {
    Properties properties = new Properties();
    final Enumeration keysEnumeration = resourceBundle.getKeys();
    while (keysEnumeration.hasMoreElements())
    {
      String key = (String) resourceBundle.getKeys().nextElement();
      properties.put(key, resourceBundle.getString(key));
    }
    processProperties(properties);
  }

  /**
   * Return the name of the theme.
   */
  public String getName ()
  {
    return _themeName;
  }

  public ColorUIResource getDesktopColor ()
  {
    return _desktopColor;
  }

  public ColorUIResource getWindowBackgroundColor ()
  {
    return _windowBackgroundColor;
  }

  public ColorUIResource getInactiveWindowBorderColor ()
  {
    return _inactiveWindowBorderColor;
  }

  public ColorUIResource getNormalBorderColor ()
  {
    return _normalBorderColor;
  }

  public ColorUIResource getDisabledBorderColor ()
  {
    return _disabledBorderColor;
  }

  public ColorUIResource getDefaultButtonBorderColor ()
  {
    return _defaultButtonBorderColor;
  }

  public ColorUIResource getNormalControlBackgroundColor ()
  {
    return _normalControlBackgroundColor;
  }

  public ColorUIResource getSelectedControlBackgroundColor ()
  {
    return _selectedControlBackgroundColor;
  }

  public ColorUIResource getSelectedControlBackgroundShadowColor ()
  {
    return _selectedControlBackgroundShadowColor;
  }

  public ColorUIResource getProgressBarBackgroundColor ()
  {
    return _progressBarBackgroundColor;
  }

  public ColorUIResource getPressedScrollBarTrackBackgroundColor ()
  {
    return _pressedScrollBarTrackBackgroundColor;
  }

  public ColorUIResource getTextInputBackgroundColor ()
  {
    return _textInputBackgroundColor;
  }

  public ColorUIResource getTextColor ()
  {
    return _textColor;
  }

  public boolean isDark ()
  {
    return _isDark;
  }

  private void processProperties(Properties properties) throws LoadException
  {
    DefaultSquarenessTheme defaultTheme = new DefaultSquarenessTheme();
    _desktopColor = getColor("desktopColor", defaultTheme.getDesktopColor(), properties);
    _windowBackgroundColor = getColor("windowBackgroundColor", defaultTheme.getWindowBackgroundColor(), properties);
    _inactiveWindowBorderColor = getColor("inactiveWindowBorderColor", defaultTheme.getInactiveWindowBorderColor(), properties);
    _normalBorderColor = getColor("normalBorderColor", defaultTheme.getNormalBorderColor(), properties);
    _disabledBorderColor = getColor("disabledBorderColor", defaultTheme.getDisabledBorderColor(), properties);
    _defaultButtonBorderColor = getColor("defaultButtonBorderColor", defaultTheme.getDefaultButtonBorderColor(), properties);
    _normalControlBackgroundColor = getColor("normalControlBackgroundColor", defaultTheme.getNormalControlBackgroundColor(), properties);
    _selectedControlBackgroundColor = getColor("selectedControlBackgroundColor", defaultTheme.getSelectedControlBackgroundColor(), properties);
    _selectedControlBackgroundShadowColor = getColor("selectedControlBackgroundShadowColor", defaultTheme.getSelectedControlBackgroundShadowColor(), properties);
    _progressBarBackgroundColor = getColor("progressBarBackgroundColor", defaultTheme.getProgressBarBackgroundColor(), properties);
    _pressedScrollBarTrackBackgroundColor = getColor("pressedScrollBarTrackBackgroundColor", defaultTheme.getPressedScrollBarTrackBackgroundColor(), properties);
    _textInputBackgroundColor = getColor("textInputBackgroundColor", defaultTheme.getTextInputBackgroundColor(), properties);
    _textColor = getColor("textColor", defaultTheme.getTextColor(), properties);

    _themeName = properties.getProperty("themeName");
    _isDark = Boolean.valueOf(properties.getProperty("isDark", "false")).booleanValue();
  }

  private ColorUIResource getColor(String colorName, ColorUIResource defaultValue, Properties properties)
     throws LoadException
  {
    ColorUIResource result = null;
    String colorString = properties.getProperty(colorName);
    if (colorString != null)
    {
      StringTokenizer tokenizer = new StringTokenizer(colorString, ",", false);
      if (tokenizer.countTokens() == 3)
      {
        try
        {
          final int red = Integer.parseInt((String) tokenizer.nextElement());
          final int green = Integer.parseInt((String) tokenizer.nextElement());
          final int blue = Integer.parseInt((String) tokenizer.nextElement());
          if ( isValidColorComponent(red) && isValidColorComponent(green) && isValidColorComponent(blue))
          {
            result = new ColorUIResource(red, green, blue);
          }
          else
          {
            throw new LoadException(colorName, "The colordefinition contains one or more wrong color components. "
                                               + "A colordefinition looks like \"colornamw=r,g,b\" where r, g and b "
                                               + "define the red, green and blue components of the color. Each of those "
                                               + "must be in the range from 0 to 255.");
          }
        }
        catch (NumberFormatException e)
        {
          throw new LoadException(colorName, "The colordefinition \""+ colorName + " = " + colorString + "\" is incorrect. "
                                             + "A colordefinition looks like \"colornamw=r,g,b\" where r, g and b "
                                             + "define the red, green and blue components of the color. Each of those "
                                             + "must be in the range from 0 to 255.");
        }
      }
      else
      {
        throw new LoadException(colorName, "The colordefinition \""+ colorName + " = " + colorString + "\" is incorrect. "
                                           + "A colordefinition looks like \"colornamw=r,g,b\" where r, g and b "
                                           + "define the red, green and blue components of the color. Each of those "
                                           + "must be in the range from 0 to 255.");
      }
    }
    else
    {
      result = defaultValue;
    }
    return result;
  }

  private boolean isValidColorComponent(int colorComponent)
  {
    return colorComponent >= 0 && colorComponent <= 255;
  }

  private ColorUIResource _desktopColor;
  private ColorUIResource _windowBackgroundColor;
  private ColorUIResource _inactiveWindowBorderColor;
  private ColorUIResource _normalBorderColor;
  private ColorUIResource _disabledBorderColor;
  private ColorUIResource _defaultButtonBorderColor;
  private ColorUIResource _normalControlBackgroundColor;
  private ColorUIResource _selectedControlBackgroundColor;
  private ColorUIResource _selectedControlBackgroundShadowColor;
  private ColorUIResource _progressBarBackgroundColor;
  private ColorUIResource _pressedScrollBarTrackBackgroundColor;
  private ColorUIResource _textInputBackgroundColor;
  private ColorUIResource _textColor;
  private String _themeName;
  private boolean _isDark;

  public static class LoadException extends Exception
  {
    /**
     */
    public LoadException (String propertyEntryName, String message)
    {
      super("Error on loading property " + propertyEntryName + " : " + message);
    }
  }
}