//==================================================================================================
// D a t a _ s t r u c t u r e                                                                 Java
// E x t e n s i o n
// E x t e n d a b l e C o n t a i n e r
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) 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 Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides an abstract class to manage a container of extendable objects. */

// Package //---------------------------------------------------------------------------------------
package bpp.data_structure.extension;

// Importation //-----------------------------------------------------------------------------------
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

@SuppressWarnings("unchecked")

// E x t e n d a b l e C o n t a i n e r  Class //--------------------------------------------------
/*CLASS ExtendableContainer */
/* Represents a container of extendable objects. It allows to manage the additional properties of
   these objets through property maps. It is an abstract class. */
public abstract class ExtendableContainer {
 //---------------------------------------------------------------------------------------Attributes
 protected int    atNext;         // Next available position for adding a property.
 protected Vector atPropertyMapS; // List of the property maps.
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD ExtendableContainer */ /* Builds an extendable container. */
 public ExtendableContainer() {
  atPropertyMapS=new Vector();
  atNext=0;
 }
 //-----------------------------------------------------------------------------------------Iterator
 /*AMETHOD ExtendableContainer */
 /* Returns an iterator over the elements of the container. Abstract method. */
 public abstract Iterator iterator(); //
 //-----------------------------------------------------------------------------------AttachProperty
 /*METHOD ExtendableContainer */
 /* Attaches a property to the container, i.e. attaches this property to all the objects of the
    container. A property map representing this property is returned. */
 public PropertyMap attachProperty(String agName,Property agProperty) {
  ExtendableObject lcExtendable;

  Iterator    lcIterator    = iterator();
  PropertyMap lcPropertyMap = null;

  if (agProperty==null) agProperty=new NullProperty();

  while (atNext<atPropertyMapS.size() && lcPropertyMap==null) {
   if (atPropertyMapS.elementAt(atNext)==null) {
    lcPropertyMap=new PropertyMap(agName,atNext,agProperty);
    atPropertyMapS.setElementAt(lcPropertyMap,atNext);
   }
   else ++atNext;
  }

  if (lcPropertyMap==null) {
   lcPropertyMap=new PropertyMap(agName,atNext++,agProperty);
   atPropertyMapS.add(lcPropertyMap);
  }

  while (lcIterator.hasNext()) {
   lcExtendable=(ExtendableObject)lcIterator.next();
   lcPropertyMap.set(lcExtendable,lcPropertyMap.template().duplicate());
  }

  return (lcPropertyMap);
 }
 //-----------------------------------------------------------------------------------DetachProperty
 /*METHOD ExtendableContainer */
 /* Detaches a property from the container, i.e. detaches this property from all the objects of the
    container. */
 public void detachProperty(PropertyMap agPropertyMap) {
  ExtendableObject lcExtendable;

  Iterator lcIterator = iterator();

  while (lcIterator.hasNext()) {
   lcExtendable=(ExtendableObject)lcIterator.next();
   agPropertyMap.set(lcExtendable,null);
  }

  atPropertyMapS.setElementAt(null,agPropertyMap.index());
  if (agPropertyMap.index()<atNext) atNext=agPropertyMap.index();
 }
 //---------------------------------------------------------------------------------AttachProperties
 protected void attachProperties(ExtendableObject agExtendable) {
  PropertyMap lcPropertyMap;

  Iterator lcIterator = propertyMaps().iterator();

  while (lcIterator.hasNext()) {
   lcPropertyMap=(PropertyMap)lcIterator.next();
   lcPropertyMap.set(agExtendable,lcPropertyMap.template().duplicate());
  }
 }
 //---------------------------------------------------------------------------------DetachProperties
 protected void detachProperties(ExtendableObject agExtendable) {
  PropertyMap lcPropertyMap;

  Iterator lcIterator = propertyMaps().iterator();

  while (lcIterator.hasNext()) {
   lcPropertyMap=(PropertyMap)lcIterator.next();
   lcPropertyMap.set(agExtendable,null);
  }
 }
 //--------------------------------------------------------------------------------------PropertyMap
 /*METHOD ExtendableContainer */
 /* Finds the property map of the container that is associated with a given name. */
 public PropertyMap propertyMap(String agName) {
  boolean     lcFound       = false;
  Iterator    lcIterator    = propertyMaps().iterator();
  PropertyMap lcPropertyMap = null;

  while (lcIterator.hasNext() && !lcFound) {
   lcPropertyMap=(PropertyMap)lcIterator.next();
   lcFound=(lcPropertyMap.name().equals(agName));
  }

  if (lcFound) return (lcPropertyMap);
  return (null);
 }
 //-------------------------------------------------------------------------------------PropertyMaps
 /*METHOD ExtendableContainer */
 /* Returns a collection of all the property maps of the container. */
 public Collection propertyMaps() {
  PropertyMap lcPropertyMap;

  Iterator lcIterator     = atPropertyMapS.iterator();
  Vector   lcPropertyMapS = new Vector();

  while (lcIterator.hasNext()) {
   lcPropertyMap=(PropertyMap)lcIterator.next();
   if (lcPropertyMap!=null) lcPropertyMapS.add(lcPropertyMap);
  }

  return (lcPropertyMapS);
 }
}

// N u l l P r o p e r t y  Class //----------------------------------------------------------------
class NullProperty implements Property {
 //----------------------------------------------------------------------------------------Duplicate
 public Property duplicate() { return (new NullProperty()); }
 //-----------------------------------------------------------------------------------------ToString
 public String toString() { return ("null"); }
 //---------------------------------------------------------------------------------------FromString
 public void fromString(String agString) throws Exception {}
}

// End //-------------------------------------------------------------------------------------------