//______________________________________________________________________________
//   |       |
//   | knipp |           Knipp Medien und Kommunikation GmbH
//    -------
//
//
//     Knipp RRI Toolkit
//
//
//     Copyright (C) 2005 by Knipp Medien und Kommunikation GmbH
//
//     This library is free software; you can redistribute it and/or
//     modify it under the terms of the GNU Lesser General Public License 
//     as published by the Free Software Foundation; either version 2.1 
//     of the License, or any later version.
// 
//     This library 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 Lesser General Public License for more details.
//
//     You should have received a copy of the GNU Lesser General
//     Public License along with this library; if not, write to the 
//     Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
//     Boston, MA 02111-1307 USA 
//
//
//     initial author:    Klaus Malorny
//
//     version:           1.3 (15112), 2011/05/27 16:00:14
//                        $Revision: 14987 $ 
//                        $Date: 2011-01-06 12:03:23 +0100 (Thu, 06 Jan 2011) $
//                        $Author: Klaus.Malorny $
//

package de.knipp.rritoolkit;

import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collections;

/**
 *  class that represents a key-value list consisting of multiple sections.
 *  each section itself is represented by a {@code KVList}. Please note
 *  that the comparison  of section names is performed case-sensitive. 
 *  Therefore, all keys are expected to be lower-case normalized.
 *
 *  @version  $Revision: 14987 $
 *  @author   Klaus Malorny
 */

public class KVMultiList
{
  /** the main key-value list */
  
  private KVList mainList;
  
  
  /** the set of all sections */
  
  private Set<Section> sections;
  

  /** mapping from the section names to the sections */
  
  private Map<String, List<Section>> nameMap;
  
  
  /** the map from the list to the section */
  
  private Map<KVList, Section> listMap;
  
  
  /**
   *  constructor
   */
  
  public KVMultiList ()
  {
    mainList = new KVList ();
    sections = new HashSet<Section> ();
    nameMap = new HashMap<String, List<Section>> ();
    listMap = new IdentityHashMap<KVList, Section> ();
  }
  

  
  
  /**
   *  return the main section
   *
   *  @return                  the main section
   */
  
  public KVList getMainSection ()
  {
    return mainList;
  }
  
  
  
  /**
   *  return the subsections with the given name
   *
   *  @param name               the name
   *  @return                   the list of key-value lists
   */
  
  public List<KVList> getSections (String name)
  {
    List<Section> list = nameMap.get (name);
    if (list == null) return Collections.emptyList ();
    List<KVList> llist = new ArrayList<KVList> ();
    
    for (Section s: list) llist.add (s.list);
    return llist;
  }
  
  
  
  /**
   *  return the first section with the given name
   *
   *  @param name               the name
   *  @return                   the first key-value list or {@code null} if
   *                            no section with the given name exists
   */
  
  public KVList getFirstSection (String name)
  {
    List<Section> list = nameMap.get (name);
    return list == null || list.isEmpty () ? null : list.get (0).list;
  }
  
  

  /**
   *  remove the given section
   *
   *  @param s                    the section to remove
   */
  
  private void removeSection (Section s)
  {
    for (String name: s.names)
    {
      List<Section> list = nameMap.get (name);
      list.remove (s);
    }  
    
    sections.remove (s);
    listMap.remove (s.list);
  }
  
  
  /**
   *  remove the section represented by the given list
   *
   *  @param list                 the list to remove
   */
  
  public void removeSection (KVList list)
  {
    Section s = listMap.get (list);
    if (s == null) return;
    removeSection (s);
  }
  
  
  
  /**
   *  create a new section with the given name(s)
   *
   *  @param names                the names
   *  @return                     the list created for the section
   */
  
  public KVList newSection (String... names)
  {
    KVList list = new KVList ();
    addSection (list, names);
    return list;
  }
  

  /**
   *  add the given list as a new section
   *
   *  @param list                 the list to add
   *  @param names                the names for the section
   */
  
  public void addSection (KVList list, String... names)
  {
    if (names.length == 0) return;   // no names, no section!
    
    // check whether the section already exists. If not, create one
    
    Section s = listMap.get (list);
    
    if (s == null)
    {
      s = new Section ();
      s.list = list;
      sections.add (s);
      listMap.put (s.list, s);
    }
    
    for (String name: names)
    {
      if (!s.names.contains (name))
      {
        s.names.add (name);
        List<Section> slist = nameMap.get (name);
        
        if (slist == null)
        {
          slist = new ArrayList<Section> ();
          nameMap.put (name, slist);
        }
        
        slist.add (s);
      }
    }
  }
  
  
  
  /**
   *  return the subsection names of the given list. The list must be 
   *  managed by this object
   *
   *  @param list                   the list of which the names shall be
   *                                return
   *  @return                       the names or {@code null} if the list
   *                                not a subsection
   */
  
  public String[] getSectionNames (KVList list)
  {
    Section s = listMap.get (list);
    if (s == null) return null;
    
    String[] names = new String[s.names.size ()];
    s.names.toArray (names);
    
    return names;
  }
  
  
  
  /**
   *  return an iterator over all subsections
   *
   *  @return                      the iterator
   */
  
  public Iterator<KVList> getSubsections ()
  {
    return listMap.keySet ().iterator ();
  }
  
  
  
  /**
   *  small class that represents a section.
   *
   *  @version  $Revision: 14987 $
   *  @author   Klaus Malorny
   */
  
  private static class Section
  {
    /** the names associated with this section */
    
    public Set<String> names;
    
    
    /** the key-value list */
    
    public KVList list;
    
    
    /**
     *  constructor
     */
    
    public Section ()
    {
      names = new HashSet<String> ();
    }
    
  }
  
  
  
}