/**
 * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.web.config;

import java.util.Map;
import java.util.Set;

import org.fudgemsg.AnnotationReflector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
import com.opengamma.core.config.Config;
import com.opengamma.util.ClassUtils;

/**
 * Provides all supported configuration types
 */
public final class ConfigTypesProvider {

  /** Logger. */
  private static final Logger s_logger = LoggerFactory.getLogger(ConfigTypesProvider.class);
  /**
   * Singleton instance.
   */
  private static final ConfigTypesProvider s_instance = new ConfigTypesProvider();

  /**
   * Map of config types.
   */
  private final ImmutableSortedMap<String, Class<?>> _configTypeMap;
  /**
   * Map of config descriptions.
   */
  private final ImmutableSortedMap<String, String> _configDescriptionMap;

  //-------------------------------------------------------------------------
  /**
   * Gets the singleton instance.
   * 
   * @return the provider, not null
   */
  public static ConfigTypesProvider getInstance() {
    return s_instance;
  }

  //-------------------------------------------------------------------------
  /**
   * Restricted constructor
   */
  private ConfigTypesProvider() {
    Map<String, Class<?>> result = Maps.newHashMap();
    ImmutableSortedMap.Builder<String, String> descriptions = ImmutableSortedMap.naturalOrder();
    AnnotationReflector reflector = AnnotationReflector.getDefaultReflector();
    Set<Class<?>> configClasses = reflector.getReflector().getTypesAnnotatedWith(Config.class);
    for (Class<?> configClass : configClasses) {
      Config configValueAnnotation = configClass.getAnnotation(Config.class);
      if (configValueAnnotation != null) {
        // extract config type
        Class<?> configType = configValueAnnotation.searchType();
        if (configType == Object.class) {
          configType = configClass;
        }
        // extract description
        String description = configValueAnnotation.description();
        if (description.length() == 0) {
          description = configType.getSimpleName();
        }
        // store
        Class<?> old = result.put(configType.getSimpleName(), configType);
        if (old != null) {
          s_logger.warn("Two classes exist with the same name: " + configType.getSimpleName());
        }
        descriptions.put(configType.getSimpleName(), description);
      }
    }
    _configTypeMap = ImmutableSortedMap.copyOf(result);
    _configDescriptionMap = descriptions.build();
  }

  //-------------------------------------------------------------------------
  /**
   * Gets the set of config keys.
   * 
   * @return the types, not null
   */
  public ImmutableSortedSet<String> getConfigTypes() {
    return ImmutableSortedSet.copyOf(_configTypeMap.keySet());
  }

  /**
   * Gets the map of config types by short key.
   * 
   * @return the map, not null
   */
  public ImmutableSortedMap<String, Class<?>> getConfigTypeMap() {
    return _configTypeMap;
  }

  /**
   * Gets the map of config descriptions by short key.
   * 
   * @return the map, not null
   */
  public ImmutableSortedMap<String, String> getDescriptionMap() {
    return _configDescriptionMap;
  }

  /**
   * Gets the description for a type.
   * 
   * @param type  the type, not null
   * @return the description, not null
   */
  public String getDescription(Class<?> type) {
    String key = HashBiMap.create(_configTypeMap).inverse().get(type);
    String description = null;
    if (key != null) {
      description = _configDescriptionMap.get(key);
    }
    return (description != null ? description : type.getSimpleName());
  }

}

@@ -210,16 +210,42 @@
 til.Set;
+%0Aimport java.util.TreeMap;
 %0A%0Aimport
@@ -570,46 +570,8 @@
 fig;
-%0Aimport com.opengamma.util.ClassUtils;
 %0A%0A/*
@@ -1120,16 +1120,121 @@
 tionMap;
+%0A  /**%0A   * Map of config groups.%0A   */%0A  private final Map%3CString, Map%3CString, String%3E%3E _configGroupMap;
 %0A%0A  //--
@@ -1621,24 +1621,61 @@
 rovider() %7B%0A
+    _configGroupMap = new TreeMap();%0A
     Map%3CStri
@@ -2335,32 +2335,114 @@
 lass;%0A        %7D%0A
+        // extract grouping%0A        String group = configValueAnnotation.group();%0A
         // extra
@@ -2917,16 +2917,339 @@
 ption);%0A
+        if (_configGroupMap.containsKey(group)) %7B%0A          _configGroupMap.get(group).put(configType.getSimpleName(), description);%0A        %7D else %7B%0A          Map%3CString, String%3E value = new TreeMap%3C%3E();%0A          value.put(configType.getSimpleName(), description);%0A          _configGroupMap.put(group, value);%0A        %7D%0A%0A
       %7D%0A
@@ -3360,16 +3360,17 @@
 uild();%0A
+%0A
   %7D%0A%0A  /
@@ -4010,32 +4010,32 @@
 criptionMap() %7B%0A
-
     return _conf
@@ -4049,32 +4049,220 @@
 iptionMap;%0A  %7D%0A%0A
+  /**%0A   * Gets the map of config groups by short key.%0A   *%0A   * @return the map, not null%0A   */%0A  public Map%3CString, Map%3CString, String%3E%3E getGroupMap() %7B%0A    return _configGroupMap;%0A  %7D%0A%0A
   /**%0A   * Gets 

create list of sorted config groups