package org.jboss.seam.excel.css;

import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;

public class StyleStringParser
{
   private static final char STYLE_SEPARATOR = ';';
   private static final String KEY_VALUE_SEPARATOR = ":";
   private static final String STYLE_SHORTHAND_SEPARATOR = " ";
   private static final char ESCAPE_CHAR = '\'';
   
   private Log log = Logging.getLog(StyleStringParser.class);
   
   private String styleString;
   private Map<String, PropertyBuilder> propertyBuilderMap;
   private StyleMap styleMap = new StyleMap();
   private boolean escaping = false;
   
   public static StyleStringParser of(String styleString, Map<String, PropertyBuilder> propertyBuilderMap)
   {
      return new StyleStringParser(styleString, propertyBuilderMap);
   }
   
   protected StyleStringParser(String styleString, Map<String, PropertyBuilder> propertyBuilderMap)
   {
      this.styleString = styleString;
      this.propertyBuilderMap = propertyBuilderMap;
   }
   
   private void addStyle(StringBuilder styleBuilder)
   {
      String styleString = styleBuilder.toString();
      int keyValueBreakpointIndex = styleString.indexOf(KEY_VALUE_SEPARATOR);
      if (keyValueBreakpointIndex < 0)
      {
         log.warn("Key-value separator character #0 not found in style #1, dropping", KEY_VALUE_SEPARATOR + styleBuilder.toString());
         return;
      }
      String styleName = styleString.substring(0, keyValueBreakpointIndex).toLowerCase().trim();
      if (!propertyBuilderMap.containsKey(styleName))
      {
         log.warn("No property builder (unknown style) for property #0", styleName);
         return;
      }
      PropertyBuilder propertyBuilder = propertyBuilderMap.get(styleName);
      String styleValue = styleString.substring(keyValueBreakpointIndex + 1);
      log.trace("Parsed style #0 to #1 => #2", styleString, styleName, styleValue);
      String[] styleValues = trimArray(styleValue.trim().split(STYLE_SHORTHAND_SEPARATOR));
      styleMap.putAll(propertyBuilder.parseProperty(styleName, styleValues));
   }
   
   public static String[] trimArray(String[] array)
   {
      List<String> validValues = new ArrayList<String>();
      for (int i = 0; i < array.length; i++)
      {
         if (!"".equals(array[i]) && !" ".equals(array[i]))
         {
            validValues.add(array[i].toLowerCase().trim());
         }
      }
      return validValues.toArray(new String[validValues.size()]);
   }
   
   public StyleMap parse()
   {
      CharacterIterator iterator = new StringCharacterIterator(styleString);
      StringBuilder styleBuilder = new StringBuilder();
      for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next())
      {
         if (ESCAPE_CHAR == c)
         {
            escaping = !escaping;
         }
         else if (STYLE_SEPARATOR == c && !escaping)
         {
            addStyle(styleBuilder);
            styleBuilder = new StringBuilder();
         }
         else
         {
            styleBuilder.append(c);
         }
      }
      if (styleBuilder.length() > 0)
      {
         addStyle(styleBuilder);
      }
      
      if (escaping)
      {
         log.warn("Unbalanced escape characters #0 in style #1", ESCAPE_CHAR, styleBuilder.toString());
      }
      return styleMap;
   }
}
