AssetUtil.java :  » Science » Cougaar12_4 » org » cougaar » glm » util » Java Open Source

Java Open Source » Science » Cougaar12_4 
Cougaar12_4 » org » cougaar » glm » util » AssetUtil.java
/*
 * <copyright>
 *  
 *  Copyright 1997-2004 BBNT Solutions, LLC
 *  under sponsorship of the Defense Advanced Research Projects
 *  Agency (DARPA).
 * 
 *  You can redistribute this software and/or modify it under the
 *  terms of the Cougaar Open Source License as published on the
 *  Cougaar Open Source Website (www.cougaar.org).
 * 
 *  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.
 *  
 * </copyright>
 */

package org.cougaar.glm.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.cougaar.glm.GLMConst;
import org.cougaar.glm.ldm.Constants;
import org.cougaar.glm.ldm.asset.Ammunition;
import org.cougaar.glm.ldm.asset.CargoShip;
import org.cougaar.glm.ldm.asset.Consumable;
import org.cougaar.glm.ldm.asset.Container;
import org.cougaar.glm.ldm.asset.Convoy;
import org.cougaar.glm.ldm.asset.GLMAsset;
import org.cougaar.glm.ldm.asset.MovabilityPG;
import org.cougaar.glm.ldm.asset.Organization;
import org.cougaar.glm.ldm.asset.Person;
import org.cougaar.glm.ldm.asset.PhysicalPG;
import org.cougaar.glm.ldm.asset.Repairable;
import org.cougaar.glm.ldm.asset.TransportationNode;
import org.cougaar.glm.ldm.asset.TransportationRoute;
import org.cougaar.glm.ldm.plan.GeolocLocation;
import org.cougaar.lib.util.UTILAsset;
import org.cougaar.lib.util.UTILPluginException;
import org.cougaar.lib.util.UTILRuntimeException;
import org.cougaar.planning.ldm.PlanningFactory;
import org.cougaar.planning.ldm.asset.AggregateAsset;
import org.cougaar.planning.ldm.asset.Asset;
import org.cougaar.planning.ldm.asset.AssetGroup;
import org.cougaar.planning.ldm.asset.NewItemIdentificationPG;
import org.cougaar.planning.ldm.asset.NewTypeIdentificationPG;
import org.cougaar.planning.ldm.asset.PropertyGroup;
import org.cougaar.planning.ldm.asset.TypeIdentificationPG;
import org.cougaar.planning.ldm.measure.Area;
import org.cougaar.planning.ldm.measure.Distance;
import org.cougaar.planning.ldm.measure.Mass;
import org.cougaar.planning.ldm.measure.Volume;
import org.cougaar.planning.ldm.plan.Relationship;
import org.cougaar.planning.ldm.plan.RelationshipSchedule;
import org.cougaar.planning.ldm.plan.Role;
import org.cougaar.planning.ldm.plan.RoleSchedule;
import org.cougaar.planning.ldm.plan.ScheduleElement;
import org.cougaar.planning.ldm.plan.Task;
import org.cougaar.util.TimeSpan;
import org.cougaar.util.log.Logger;


/**
 * This class contains utility functions for getting
 * Assets.
 */

public class AssetUtil extends UTILAsset {
  private static String myName = "AssetUtil";
  private static final long BTWN_AVAIL_TOLERANCE = 3600000l;
  private static double MAX_CUBIC_FT = 1.0d;
  private static double MAX_SQ_FT = 1.0d;
  public static final Role CARGO_PORT_ROLE = GLMConst.GENERIC_SEA_PORT;
  public static final Role AMMO_PORT_ROLE = GLMConst.AMMUNITION_SEA_PORT;
  public static final Role AMMO_PORT_ROLE_ALT = GLMConst.AMMO_SEA_PORT;

  public AssetUtil (Logger logger) { 
    super (logger); 
    glmPrepHelper = new GLMPrepPhrase (logger);
    glmPrefHelper = new GLMPreference (logger);
    measureHelper = new GLMMeasure    (logger);
  }

  public final Convoy makeConvoy(PlanningFactory root, String uniqueID){
    Convoy convoy = null;
    try{
      NewTypeIdentificationPG p1 = null;

      convoy = (Convoy) root.createAsset(Class.forName ("org.cougaar.glm.ldm.asset.Convoy"));
      p1 = (NewTypeIdentificationPG)convoy.getTypeIdentificationPG();
      p1.setTypeIdentification("TOPS_CONVOY");
      p1.setNomenclature("Convoy");
      ((NewItemIdentificationPG)
       convoy.getItemIdentificationPG()).setItemIdentification(uniqueID);
    }
    catch(Exception e){
      throw new UTILRuntimeException(e.getMessage());
    }
    return (convoy);
  }

  /**
   * These control how big something must be before it is made into
   * distinct assets instead of remaining within an aggregate asset.
   */

  public void setMaxCubicFt (double max) { MAX_CUBIC_FT = max; }
  public void setMaxSqFt    (double max) { MAX_SQ_FT = max; }

  /** 
   * Utility method for finding organization/cluster assets. 
   * @param assets the Enumeration of assets received from the asset container
   * @param desiredRole a string describing the capable role of an organization
   *        the string is defined in the mycluster-prototype-ini.dat file in 
   *        the topsconfig directory.
   * @return Organization that has the role described in desiredRole 
   */
  public Organization getOrgAsst(Iterator assets, String desiredRole){
    while (assets.hasNext()){
      Asset resource = (Asset)assets.next();
      if (resource instanceof Organization) {
  Organization org = (Organization)resource;
  if (org.isSelf()){
    RelationshipSchedule schedule = org.getRelationshipSchedule();

    Collection orgCollection = 
      schedule.getMatchingRelationships(Role.getRole(desiredRole));
    if (!orgCollection.isEmpty()) {
      Relationship rel = (Relationship)orgCollection.iterator().next();
      Organization o = (Organization)schedule.getOther(rel);
      return o;
    }
  }
      }
    }
    return null;
  }

  /** 
   * Utility method for finding organization/cluster assets. 
   * @param assets the Enumeration of assets received from the asset container
   * @param desiredRole a string describing the capable role of an organization
   *        the string is defined in the mycluster-prototype-ini.dat file in 
   *        the topsconfig directory.
   * @return Organization that has the role described in desiredRole 
   */
  public List getOrgAssts(Iterator assets, String desiredRole){
    ArrayList orgs = new ArrayList();
    while (assets.hasNext()){
      Asset resource = (Asset)assets.next();
      if (resource instanceof Organization) {
  Organization org = (Organization)resource;
  if (org.isSelf()){
    RelationshipSchedule schedule = org.getRelationshipSchedule();

    Collection orgCollection = 
      schedule.getMatchingRelationships(Role.getRole(desiredRole));
    if (!orgCollection.isEmpty()) {
      for (Iterator i = orgCollection.iterator(); i.hasNext();){
        Relationship rel = (Relationship)i.next();
        Organization o = (Organization)schedule.getOther(rel);
        orgs.add(o);

      }
      return orgs;
    }
  }
      }
    }
    return null;
  }


  /**
   * get the GeolocoLocation of an organization
   * @param o the organization
   */
  public GeolocLocation getOrgLocation(Organization o) {
    GeolocLocation geoloc;

    try {
      geoloc = (GeolocLocation) o.getMilitaryOrgPG().getHomeLocation();
    } catch (NullPointerException e) {
      throw new UTILPluginException("no military org property for organization"
            + " (" + o + ")");
    }

    return geoloc;
  }

  /**
   * creates a HashMap of organizations with their geolocCodes as keys.
   * @param organizations the en of organizations to be put in the hashmap
   * @return HashMap the newly constructed table with geolocCodes as keys,
   *         and the corresponding organization as object.
   */

  public HashMap orgAssetLocation (List organizations) {
    HashMap orgAssetTable = new HashMap();
    //    while (organizations.hasMoreElements()){
    for (Iterator iterator = organizations.iterator(); iterator.hasNext();){
      Organization org = (Organization)iterator.next();
      String geolocCode = getOrgLocation(org).getGeolocCode();
      List orgsAtGeoLoc;
      if ((orgsAtGeoLoc = (List) orgAssetTable.get(geolocCode)) == null) {
  orgsAtGeoLoc = new ArrayList ();
  orgAssetTable.put(geolocCode, orgsAtGeoLoc);
      }
      orgsAtGeoLoc.add (org);
    }
    return orgAssetTable;
  }

  /**
   * Finds the organization with the given geolocCode in the given table.
   * @param table the table to search
   * @param geolocCode the string to search for
   * @return Organization the organization with the geolocCode.
   */

  public Organization getOrg (HashMap table, String geolocCode) {
    return ((Organization)((List)table.get(geolocCode)).get(0));
  }

  public List getOrgList (HashMap table, String geolocCode) {
    return ((List)table.get(geolocCode));
  }

  public boolean hasOrg (HashMap table, String geolocCode) {
    return (getOrgList (table, geolocCode) != null);
  }

  /**
   * This call gets oneself as an organization asset.
   * @param clusterAssets the En of assets received from the asset container
   * @return Organization which represents current cluster
   */
  public Organization getSelf(Enumeration clusterAssets){
    Organization myself = null;
    while(clusterAssets.hasMoreElements()){
      Asset a = (Asset)clusterAssets.nextElement();
      if ((a instanceof Organization) &&
          (((Organization)a).isSelf())) {
        myself = (Organization)a;
        break;
      }
    }
    if(myself == null){
      throw new UTILPluginException("can't find myself as clusterAsset");
    }
    return myself;
  }


  /**
   * check to see if an asset represents a consumable
   * @param asset the asset to check
   * @return boolean
   */
  public boolean isConsumable(Asset asset){
    if(asset instanceof AggregateAsset){
      return isConsumable(((AggregateAsset)asset).getAsset());
    }
    return (asset instanceof Consumable);
  }
  
  /**
   * check to see if an asset represents a repairable
   * @param asset the asset to check
   * @return boolean
   */
  public boolean isRepairable(Asset asset){
    if(asset instanceof AggregateAsset){
      return isRepairable(((AggregateAsset)asset).getAsset());
    }
    return (asset instanceof Repairable);
  }

  /**
   * check to see if an asset represents a passenger
   * @param asset the asset to check
   * @return boolean
   */ 
  public boolean isPassenger(Asset asset) {
    if (asset instanceof AggregateAsset) {
      return isPassenger(((AggregateAsset)asset).getAsset());
    }
    else if (asset instanceof Person) {
      return true;
    }

    TypeIdentificationPG typeofasset = null;
    typeofasset = asset.getTypeIdentificationPG();
    if (typeofasset == null) {
      throw new UTILPluginException("bad type identification property: \"" +
            asset + "\"");
    }
    String nom = typeofasset.getTypeIdentification();
    if (nom == null) {
      throw new UTILPluginException("bad type identification: \"" +
            asset + "\"");
    }
    return(nom.equals("OTHER/Passenger") ||
     nom.equals("OTHER/People")||
     nom.equals("OTHER/person"));
  }

  /**
   * check to see if an asset represents a Pallet
   * @param asset the asset to check
   * @return boolean
   */ 
  public boolean isPallet(Asset asset) {
    if (asset instanceof AggregateAsset) {
      return isPallet(((AggregateAsset)asset).getAsset());
    } 
    
    if ((asset instanceof Container) || (asset instanceof org.cougaar.glm.ldm.asset.Package)){
      TypeIdentificationPG typeofasset = null;
      typeofasset = asset.getTypeIdentificationPG();
      if (typeofasset == null) {
  throw new UTILPluginException("bad type identification property: \"" +
              asset + "\"");
      }
      String nom = typeofasset.getTypeIdentification();
      if (nom == null) {
  throw new UTILPluginException("bad type identification: \"" +
              asset + "\"");
      }
      if (nom.equals ("TOPS_PALLET"))
  throw new UTILPluginException("AssetUtil.isPallet - found TOPS_PALLET.  " + 
              "Please use PALLET from Container protos instead!");
      //!!!Hack for AEF...until we figure out the TypeIdentification/Nomenclature problem on AEF's end.
      if ( (nom.indexOf("463L") != -1))
  return true;
      return(nom.equals("OTHER/Air_Pallet") ||
       nom.equals("PALLET") ||
       nom.equals("463L PLT") );
    }
    return false;
  }
  /**
   * check to see if an asset represents ammo
   *
   * works with an aggregate asset too.
   *
   * Something is ammo it's an instance of org.cougaar.glm.ldm.asset.Ammunition OR
   * The type identification PG's nomenclature is Ammunition
   *
   * @see org.cougaar.glm.ldm.asset.Ammunition
   * @param asset the asset to check
   * @return boolean
   */
  public boolean isAmmo(Asset asset) {

    if (asset instanceof AssetGroup) {
      Vector assetVector = ((AssetGroup)asset).getAssets();
      boolean ammo = false;
      for(int i = 0; i < assetVector.size(); i++) {
  boolean currentAsset = isAmmo((Asset)assetVector.elementAt(i));
  if (((ammo == true) && (currentAsset == false)) ||
      ((ammo == false && i > 0) && (currentAsset == true))) {
    throw new UTILRuntimeException("Couldn't handle AssetGroup containing Ammo and non-Ammo!");
        }
  ammo = currentAsset;
      }
    }
    boolean ammo = false;

    if (asset instanceof AggregateAsset)
      return isAmmo(((AggregateAsset)asset).getAsset());

    if (asset instanceof Ammunition)
      return true;

    if (asset instanceof AssetGroup) {
      Vector vector = (Vector)((AssetGroup)asset).getAssets();
      return isAmmo((Asset)vector.elementAt(0));
    }

    MovabilityPG mpg = 
      (MovabilityPG) ((GLMAsset)asset).getMovabilityPG();
    if(mpg != null){
      String code = mpg.getCargoCategoryCode();
      if(code != null && CargoCategoryDecoder.isAmmo(code))
  return true;
    }

    TypeIdentificationPG typeofasset = null;
    typeofasset = asset.getTypeIdentificationPG();
    if (typeofasset == null) {
      throw new UTILPluginException("bad type identification property: \"" +
            asset + "\"");
    }
    String nom = typeofasset.getTypeIdentification();
    if (nom == null) {
      throw new UTILPluginException("bad type identification: \"" + asset + "\"");
    }
    return (nom.equals("Ammunition"));
  }

  /**
   * <pre>
   * See if a task is a prepo task (i.e. 
   * already packed in a ship hanging arround
   * in the middle of the ocean somewhere).
   *
   * The check is made to see if the task has a WITH
   * preposition.
   * We look up the ship referred to by the String (Ship ID) 
   * in GlobalSea, where the ships are owned.
   *
   * </pre>
   * @param t task to check
   * @return boolean
   */
  public boolean isPrepoTask(Task t){
    if(glmPrepHelper.hasPrepNamed(t, Constants.Preposition.WITH)){
      Object o = glmPrepHelper.getIndirectObject(t, Constants.Preposition.WITH);
      return o instanceof CargoShip || o instanceof String;
    }
    return false;
  }

  /**
   * <pre>
   * convert an AssetGroup/AggregateAsset into it's component assets,
   * recursing through any contained AssetGroup/AggregateAssets as
   * needed.
   *
   * Note : Convoys are AssetGroups, so the contents of the convoy
   * will also appear on the result list.
   *
   * Will take an aggregate asset and create new instances that are
   * copies of the asset of the aggregation.  These will have
   * item id's like "xxx-7_of_9_from_yyy", where xxx is the original id, 
   * the quantity of the aggregate asset is 9, and yyy is the number of times
   * this method has been called.  Yes, you might ask, why not use the
   * aggregate's UID?  Well this seems to be null.  Why not the agg's asset? 
   * Well, this is just a prototype, so two different aggregations will
   * have the same asset, giving us the same UID.
   *
   * This allows the receipt of two aggregates of the same type of object
   * creating distinct subobjects.  Otherwise a M1A1-7_of_9 from one aggregate
   * would be equals() and hashcode() equal to a M1A1-7_of_9 from another.  
   * This is needed since now Assets are equal on the basis of type and item
   * PG equality.  (01/23/99 GWFV)
   * 
   * Will not break up aggregate
   * assets where the items are smaller than one cubic foot.
   *
   * </pre>
   * @param asset AssetGroup/AggreateAsset to divide
   * @return Vector of sub-objects
   */
  public Vector ExpandAsset(PlanningFactory theFactory, Asset asset) {
    Vector retval = new Vector();

    if (asset instanceof AssetGroup) {
      AssetGroup group = (AssetGroup)asset;
      Vector subobjects = group.getAssets();

      for (int i=0; i<subobjects.size(); i++) {
  Object subobject = subobjects.elementAt(i);
  if (subobject instanceof AssetGroup ||
      subobject instanceof AggregateAsset) {
    Vector moreboxes = ExpandAsset(theFactory, (Asset)subobject);
    for (int j = 0; j < moreboxes.size(); j++)
      retval.addElement(moreboxes.elementAt(j));
  } 
  else{
    retval.addElement(subobject);
  }
      }
    } 
    else if (asset instanceof AggregateAsset) {
      AggregateAsset aggregate = (AggregateAsset) asset;

      long count = aggregate.getQuantity();
      Asset subobject = (Asset)aggregate.getAsset();
      if (subobject instanceof AggregateAsset ||
    subobject instanceof AssetGroup) {
  for (long i=0; i<count; i++) {
    Vector evenmoreboxes = ExpandAsset(theFactory, (Asset)subobject);
    for (int j = 0; j < evenmoreboxes.size(); j++)
      retval.addElement(evenmoreboxes.elementAt(j));
  } 
      }
      else if (subobject instanceof Asset) {
  boolean tooBig = false;

        PhysicalPG ppg = 
          (PhysicalPG) ((GLMAsset)subobject).getPhysicalPG();
  if (ppg != null) {
    try {
      Volume vol  = ppg.getVolume();
      Area   area = ppg.getFootprintArea();
    
      if ((vol.getCubicFeet   () > MAX_CUBIC_FT) || 
    (area.getSquareFeet () > MAX_SQ_FT))
        tooBig = true;
    } catch (Exception e) {
      logger.warn ("AssetUtil.ExpandAsset - ERROR : " +
       "aggregate asset\n\t" + aggregate + 
       "\n\thas asset\n\t" +
       subobject + 
       "\n\tthat has no physicalPG.");
    }
  }
  if (tooBig) {
    synchronized (this) {
      for (long i=0; i<count; i++) {
        String name = getTypeName (subobject);
        if (name.length () > 10)
    name = name.substring (0, 9) + "...";

        name = name + "-" + 
    (i+1) + "_of_" + 
    count + "(" + 
    getLatestUID () + ")";
        Asset particle = theFactory.createInstance (subobject, name);
        Enumeration otherProps = asset.getOtherProperties();
        while (otherProps.hasMoreElements()) {
    particle.addOtherPropertyGroup((PropertyGroup)otherProps.nextElement());
        }
        retval.addElement(particle);
      }
    }
  }
  else
    retval.addElement (asset);
      }
      else {
  logger.error ("AssetUtil.ExpandAsset - ERROR : " +
          "aggregate asset\n\t" + aggregate + 
          "\n\thas asset\n\t" +
          subobject + 
          "\n\tthat is not an Asset.");
  retval.addElement (asset);
      }
    } 
    else{
      retval.addElement(asset);
    }
    
    return retval;
  }

  protected int latestUID = 0;
  protected synchronized int getLatestUID () {
    if (latestUID == Integer.MAX_VALUE)
      latestUID = 0;
    return ++latestUID;
  }

  /**
   * get the total Area of an asset regardless of whether it's
   * an Asset, AssetGroup, AggregateAsset, or whatever
   * @param asset the asset
   * @return Area the total area of the asset
   */
  public Area totalArea(Asset asset) {
    return totalArea (asset, false);
  }

  /**
   * get the total Area of an asset regardless of whether it's
   * an Asset, AssetGroup, AggregateAsset, or whatever
   * BUT adjusted for the peculiar semantics of asset handling in GlobalSea
   * >Vehicles only have footprint area
   * >Containers only have volume
   * 
   * @param asset the asset
   * @return Area the total area of the asset
   */
  public Area totalAdjustedArea(Asset asset) {
    return totalArea (asset, true);
  }

  public Area totalArea(Asset asset, boolean ignoreContainers) {
    if (asset instanceof AggregateAsset) {
      AggregateAsset aggAsset = (AggregateAsset)asset;
      double qty = aggAsset.getQuantity();

      if (qty <= 0)
  throw new UTILPluginException("got bad qty for Aggregate Asset: \"" + 
              asset + "\"");

      asset = aggAsset.getAsset();

      if(asset == null)
  throw new UTILPluginException("Got null asset in Aggregate Asset");

      double area = getArea(asset).getSquareFeet();
      return Area.newSquareFeet(qty * area);
    }
    else if (asset instanceof AssetGroup) {
      double d = 0.0d;
      Vector subassets = ((AssetGroup)asset).getAssets();
      for (int i = 0; i < subassets.size (); i++)
  d += totalArea((Asset)subassets.elementAt(i)).getSquareFeet();

      return Area.newSquareFeet(d);
    }

    if (ignoreContainers)
      return isVehicleOrAircraft(asset) ? getArea (asset) : Area.newSquareFeet(0.0d);

    return getArea (asset);
  }

  private Area getArea (Asset asset) {
    PhysicalPG prop = null;
    try{
      prop = (PhysicalPG) ((GLMAsset)asset).getPhysicalPG();
    }
    catch(Exception e){
      throw new UTILPluginException("error getting physical property for asset :\"" +
            asset + "\"");
    }
    Area area;
    try { area = prop.getFootprintArea(); }
    catch (Exception e) {
      throw new UTILPluginException("No Physical property set for asset: \"" +
            asset + "\"");
    }
    if (area == null) {
      throw new UTILPluginException("Got null footprint area in asset: \"" +
            asset + "\"");
    }
    return area;
  }

  /**
   * get the total Volume of an asset
   * ( regardless of whether it's
   * an Asset, AssetGroup, AggregateAsset, or whatever)
   * @param asset the asset
   * @return Volume the total volume of the asset
   */
  public Volume totalVolume(Asset asset) {
    return totalVolume(asset, false);
  }

  /**
   * get the total Volume of an asset
   * ( regardless of whether it's
   * an Asset, AssetGroup, AggregateAsset, or whatever)
   * @param asset the asset
   * @return Volume the total volume of the asset
   */
  public Volume totalAdjustedVolume(Asset asset) {
    return totalVolume(asset, true);
  }

  public Volume totalVolume(Asset asset, boolean ignoreVehiclesAndContainers) {
    if (asset instanceof AggregateAsset) {
      AggregateAsset aggAsset = (AggregateAsset)asset;
      double qty = aggAsset.getQuantity();

      if (qty <= 0)
   throw new UTILPluginException("got bad qty for Aggregate Asset: \"" + 
               asset + "\"");

      asset = aggAsset.getAsset();

      if(asset == null)
   throw new UTILPluginException("Got null asset in Aggregate Asset");

      double m3perasset = totalVolume(asset,ignoreVehiclesAndContainers).getCubicMeters();
      return Volume.newCubicMeters(qty * m3perasset);
    }
    else if (asset instanceof AssetGroup) {
      double d = 0.0d;
      Vector subassets = ((AssetGroup)asset).getAssets();
      for (int i = 0; i < subassets.size (); i++)
  d += totalVolume((Asset)subassets.elementAt(i),ignoreVehiclesAndContainers).getCubicMeters();

      return Volume.newCubicMeters(d);
    }

    if (ignoreVehiclesAndContainers)
      return (!isVehicleOrAircraft(asset) && !isStandardContainer(asset)) 
  ? getVolume (asset) : Volume.newCubicMeters(0.0d);

    return getVolume (asset);
  }

  private Volume getVolume (Asset asset) {
    PhysicalPG prop = null;
    try{ prop = (PhysicalPG) ((GLMAsset)asset).getPhysicalPG(); }
    catch(Exception e){
      throw new UTILPluginException("error getting physical property for asset :\"" +
            asset + "\"");
    }

    Volume vol;
    try { vol = prop.getVolume(); }
    catch (Exception e) {
      throw new UTILPluginException("No Physical property set for asset: \"" +
            asset + "\"");
    }
    if (vol == null) {
      throw new UTILPluginException("Got null volume in asset: \"" +
            asset + "\"");
    }
    return vol;
  }

  /**
   * get the total Mass of an asset
   * ( regardless of whether it's
   * an Asset, AssetGroup, AggregateAsset, or whatever)
   * @param asset the asset
   * @return Mass the total mass of the asset
   */

  public Mass totalMass(Asset asset) {
    if (asset instanceof AggregateAsset) {
      AggregateAsset aggAsset = (AggregateAsset)asset;
      double qty = aggAsset.getQuantity();

      if (qty <= 0)
   throw new UTILPluginException("got bad qty for Aggregate Asset: \"" + 
               asset + "\"");

      asset = aggAsset.getAsset();

      if(asset == null)
   throw new UTILPluginException("Got null asset in Aggregate Asset");

      double tonsperasset = totalMass(asset).getTons();
      return Mass.newTons(qty * tonsperasset);
    }
    else if (asset instanceof AssetGroup) {
      double d = 0.0d;
      Vector subassets = ((AssetGroup)asset).getAssets();
      for (int i = 0; i < subassets.size (); i++)
  d += totalMass((Asset)subassets.elementAt(i)).getTons();

      return Mass.newTons(d);
    }

    return getMass (asset);
  }

  private Mass getMass (Asset asset) {
    PhysicalPG prop = null;
    try{ prop = (PhysicalPG) ((GLMAsset)asset).getPhysicalPG(); }
    catch(Exception e){
      throw new UTILPluginException("error getting physical property for asset :\"" +
            asset + "\"");
    }

    Mass mass;
    try { mass = prop.getMass(); }
    catch (Exception e) {
      throw new UTILPluginException("No Physical property set for asset: \"" +
            asset + "\"");
    }
    if (mass == null) {
      throw new UTILPluginException("Got null mass in asset: \"" +
            asset + "\"");
    }
    return mass;
  }

  public long totalContainers(Asset asset) {
    if (asset instanceof AggregateAsset) {
      AggregateAsset aggAsset = (AggregateAsset)asset;
      double qty = aggAsset.getQuantity();

      if (qty <= 0)
   throw new UTILPluginException("got bad qty for Aggregate Asset: \"" + 
               asset + "\"");

      asset = aggAsset.getAsset();

      if(asset == null)
   throw new UTILPluginException("Got null asset in Aggregate Asset");

      if (isStandardContainer(asset)) return (long)qty;
      else return 0l;
    } else if (asset instanceof AssetGroup) {
      long d = 0l;
      Vector subassets = ((AssetGroup)asset).getAssets();
      for (int i = 0; i < subassets.size (); i++)
  if (isStandardContainer((Asset)subassets.elementAt(i))) d++;
      return d;
    }
    return isStandardContainer(asset) ? 1 : 0;
  }  

  /**
   * helper function, gets the total square feet footprint of an asset
   * ( regardless of whether it's
   * an Asset, AssetGroup, AggregateAsset, or whatever)
   * @param asset the asset
   * @return double the area of the asset in sqr. ft.
   */
  public double totalSquareFeet(Asset asset) {
    double area = totalArea(asset).getSquareFeet();
    if(area < 0){
      throw new UTILPluginException("Got bad area in asset: \"" +
             asset + "\"");
    }
    return area;
  }

  /**
   * helper function, gets the total volume of an asset
   * ( regardless of whether it's
   * an Asset, AssetGroup, AggregateAsset, or whatever)
   * @param asset the asset
   * @return double the volume of the asset in cubic meters
   */
  public double totalCubicMeters(Asset asset) {
    double vol = totalVolume(asset).getCubicMeters();
    if(vol < 0){
      throw new UTILPluginException("Got bad volume in asset: \"" +
            asset + "\"");
    }
    return vol;
  }

  /**
   * helper function, gets the total mass of an asset
   * ( regardless of whether it's
   * an Asset, AssetGroup, AggregateAsset, or whatever)
   * @param asset the asset
   * @return double the mass of the asset in cubic meters
   */
  public double totalTons(Asset asset) {
    double mass = totalMass(asset).getTons();
    if(mass < 0){
      throw new UTILPluginException("Got bad weight in asset: \"" +
            asset + "\"");
    }
    return mass;
  }

  /** 
   * Necessary for accurate ship location computation.
   * NOTE that travel isn't taken into account in that if the time specified
   * is in the middle of the time when the asset is traveling between tasks, 
   * the position reported will be the end of the last task.  This is as intended.
   *
   * If the time specified is in the middle of a task, we interpolate. (!!FIXIT!!)
   * 
   * @return GeolocLocation representing the current position of the asset
   *    at the time specified.  returns null if none found
   */
  public GeolocLocation getMostRecentKnownPosition(Asset a, Date time) {
    RoleSchedule rs = a.getRoleSchedule();

    // The task immediately previous (possibly including) now
    Task most_recent_task = findClosestRoleScheduleTask(rs, time, 
              true/*previous tasks*/);

    if (most_recent_task == null) {

      //        System.err.println("AssetUtil.getCurrentPosition for asset " + 
      //         a.getUID() + " at time " + time + 
      //         " found no previous tasks");
      return null;
    }
        
    if (prefHelper.getLateDate(most_recent_task).after(time)) 
      return glmPrepHelper.getFromLocation(most_recent_task);
    /*
      {
      // If the last one overlaps the time, we need to interpolate
      GeolocLocation start = glmPrepHelper.getFromLocation(most_recent_task);
      GeolocLocation end = glmPrepHelper.getToLocation(most_recent_task);      
      }
    */

    return glmPrepHelper.getToLocation(most_recent_task);
  }

  /**
   * Check to see if the task fits in the role schedule of the asset.
   * DON'T perform any allocation, assignment, etc. just check for 
   * enough space.
   * FOR NOW, (!!FIXIT!!) we're assuming the ship is EMPTY unless 
   * fully allocated, i.e. you have to manage the loading yourself 
   * without actually adding something on the ship until you add 
   * everything in one big block.  You can actually get into the guts
   * of the asset and check the role schedule for yourself if you really
   * want to, but it's kind of ugly.
   * 
   * There are two possible legal cases (i.e. no nulls or other errors) in
   * which this method will return false:  the role schedule doesn't have
   * availability for a task, or the role schedule already has plan elements
   * in the time window where we want the task to fit that make the schedule
   * unfeasible.
   */
  public boolean checkTaskAgainstRoleSchedule(Asset a, Task t) {
    boolean taskOK = false;

    GeolocLocation t_start_loc = (GeolocLocation)
      t.getPrepositionalPhrase(Constants.Preposition.FROM).getIndirectObject();
    // We assume the VIA is irrelevant
    GeolocLocation t_end_loc = (GeolocLocation)
      t.getPrepositionalPhrase(Constants.Preposition.TO).getIndirectObject();
    
    Date t_start_time = prefHelper.getReadyAt(t);
    Date t_end_time = prefHelper.getLateDate(t);
    
    // We need to make sure a) the asset is available in this time window
    // b) the asset can get to the start location by the start time and
    // c) the asset can get to its next commitment after the end time 
    RoleSchedule a_rs = a.getRoleSchedule();
  
    // Note that these aren't really the start and end of the travel of the
    // asset, they're the tasks that the asset can start travel at the EARLIEST
    // and the date by which the asset must at the LATEST be somewhere else.
    Task t_start_trvl_task = 
      findClosestRoleScheduleTask(a_rs, t_start_time, true); // Check earlier
    Task t_end_trvl_task =  
      findClosestRoleScheduleTask(a_rs, t_end_time, false); // Check later

    // First check is to make sure the transport asset for this mission can
    // get where it needs to be on time (NOTE - this prefers the status quo,
    // i.e. tasks already allocated get preference.  is that ok?)
    // Should we be robust for nulls here?
    Distance start_d = 
      measureHelper.distanceBetween((GeolocLocation)
            t_start_trvl_task.getPrepositionalPhrase(Constants.Preposition.TO).getIndirectObject(),
            t_start_loc);
    //     Date t_start_trvl = new Date(t_start_time.getTime() -
    //          travelTimeUsingAsset(start_d,a));

    long t_start_trvl = (t_start_time.getTime() - travelTimeUsingAsset(start_d,a));

    //    if (t_start_trvl.before(prefHelper.getLateDate(t_start_trvl_task))) {
    if (t_start_trvl < (prefHelper.getLateDate(t_start_trvl_task).getTime())) {
      //System.err.println("Could not get to start in time using this mission");
      taskOK = false;
      return taskOK;
    }

    Distance end_d = measureHelper.distanceBetween(t_end_loc,
               (GeolocLocation)t_end_trvl_task.getPrepositionalPhrase(Constants.Preposition.FROM).getIndirectObject());
    //     Date t_end_trvl = new Date(t_end_time.getTime() +
    //              travelTimeUsingAsset(end_d,a));
    long t_end_trvl = (t_end_time.getTime() + travelTimeUsingAsset(end_d,a));

    //    if (prefHelper.getReadyAt(t_end_trvl_task).before(t_end_trvl)) {
    if (prefHelper.getReadyAt(t_end_trvl_task).getTime() < (t_end_trvl)) {
      //System.err.println("Could not get to next task in time using this mission");
      taskOK = false;
      return taskOK;
    }
    
    
    // get a container of plan elements that have dates in the
    // given range
    Collection rs_avail_elts = 
      a_rs.getOverlappingRoleSchedule(t_start_trvl, t_end_trvl);
    
    // if the above query returns anything, that means that we can't insert
    // the task because it would overlap an already-existing block
    if (rs_avail_elts.size() != 0) {
      taskOK = false;
      return taskOK;
    }

    // make sure we have availability throughout the time range of the task
    Collection avail_s = 
      a_rs.getAvailableSchedule().getOverlappingScheduleElements(t_start_trvl, 
                 t_end_trvl);
    
    Iterator avail_iter = avail_s.iterator();

    //    Date last_date_checked = t_start_trvl;
    long last_date_checked = t_start_trvl;
    while (avail_iter.hasNext()) {
      ScheduleElement next_se = (ScheduleElement) avail_iter.next();
      
      if (!(next_se.included(last_date_checked))) {
  taskOK = false;
  return taskOK;
      }
      if (next_se.included(t_end_trvl)) {
  taskOK = true;
  return taskOK;
      } else {
  //   last_date_checked = new Date(next_se.getEndDate().getTime() + 
  //              BTWN_AVAIL_TOLERANCE);
  last_date_checked = next_se.getEndDate().getTime() + BTWN_AVAIL_TOLERANCE;
      }
    }
    
    return taskOK;
  }

  // !!FIXIT!! Hack!  
  /**
   * Utility method to return the approximate time the given asset requires
   * to go Distance d
   */
  private long travelTimeUsingAsset(Distance d, Asset a) {
    // 100 thousand seconds, or a little over a day (27.77... hours)
    return 100000000l;
  }
  
  /**
   * Looks for Allocation (is this correct?) plan element that contains
   * a task immediately previous (check_backwards is true) or after (false)
   * the time given in the RoleSchedule.
   * Do we need to check the role in this allocation as well?
   * @return null if no task found
   */
  /** 
   * Inefficient...
   * @return string that lists the nodes in the route 
   */
  public String getNodeNames (TransportationRoute route) {
    String nodes = "";
    for (Iterator i = route.getNodes().iterator(); i.hasNext ();) {
      nodes = nodes + " " + ((TransportationNode) i.next()).getDescription();
    }
    return nodes;
  }

  /**
   * Determines if the asset passed in is a standard container or not
   */
  public boolean isStandardContainer(Asset a)
  {
    return (a instanceof Container);
  }

  /**
   * Determines if the asset passed in is a vehicle (for purposes of ship 
   * loading) or not.
   **/
  public boolean isVehicle(Asset a){
    MovabilityPG mpg = 
      (MovabilityPG) ((GLMAsset)a).getMovabilityPG();
    if(mpg == null)
      return false;
    String code = mpg.getCargoCategoryCode();

    boolean retval = false;
    
    try {
      retval = CargoCategoryDecoder.isRORO(code);
    } catch (NullPointerException npe) {
      throw new UTILRuntimeException("GMLAsset.isVehicle - asset has movability PG but " + 
             "cargo category code is NOT set.\nMovability PG was :" + mpg + 
             "\nAsset was " + a);
    }
    
    return retval;
  }

  /**
   * Determines if the asset passed in is a vehicle (for purposes of ship 
   * loading) or not OR is a crated aircraft.
   * 
   * These items are packed on ship by area.
   **/
  public boolean isVehicleOrAircraft(Asset a){
    MovabilityPG mpg = 
      (MovabilityPG) ((GLMAsset)a).getMovabilityPG();
    if(mpg == null)
      return false;
    String code = mpg.getCargoCategoryCode();
    boolean isAircraft = (code.toUpperCase().charAt(0) == 'B');
    return (isAircraft || CargoCategoryDecoder.isRORO(code));
  }

  /**
   * Utility method - find the organization corresponding to the port at 
   * the given location
   * @param loc he location
   * @param ports_en a list of ports to search: probably obtained by a call to
   * getOrganizationAssets()
   * @param myClusterName used for logger.isDebugEnabled()()ging purposes.
   * @return the port that matches the location.
   */
  public Organization findPortOrg(GeolocLocation loc, 
                                         Enumeration ports_en,
                                         String myClusterName) {
    Set ports = new HashSet();
    while (ports_en.hasMoreElements()) {
      Organization org = (Organization)ports_en.nextElement();
      RelationshipSchedule sched = org.getRelationshipSchedule();
      
      Collection portRelationships;
      
      //BOZO - Should be looking at self org for providers. Don't have self org so 
      //will look to see if org has any port customers.
      if (!((portRelationships = 
       sched.getMatchingRelationships(GLMConst.THEATER_SEA_PROVIDER.getConverse(),
              TimeSpan.MIN_VALUE,
              TimeSpan.MAX_VALUE)).isEmpty()) ||
          !((portRelationships = 
       sched.getMatchingRelationships(GLMConst.GENERIC_SEA_PORT.getConverse(),
              TimeSpan.MIN_VALUE,
              TimeSpan.MAX_VALUE)).isEmpty()) ||
          !((portRelationships = 
       sched.getMatchingRelationships(GLMConst.AMMUNITION_SEA_PORT.getConverse(),
              TimeSpan.MIN_VALUE,
              TimeSpan.MAX_VALUE)).isEmpty())) {
        for (Iterator iterator = portRelationships.iterator();
             iterator.hasNext();) {
          Relationship relationship = (Relationship) iterator.next();
          ports.add(sched.getOther(relationship));
        }
      }
    }
    
    Organization foundOrg = measureHelper.bestOrg(loc, ports, myClusterName);
    return foundOrg;
  }
  
  /** 
   * test if port is an ammo port
   * @param p Organization to be tested
   * @return true if is an ammo port
   */
  public boolean isAmmoPort(Asset p) {
    if (p instanceof Organization) {
      RelationshipSchedule schedule = 
        ((Organization)p).getRelationshipSchedule();
      //      return (!(schedule.getMatchingRelationships(AMMO_PORT_ROLE).isEmpty())) ||
      //     (!(schedule.getMatchingRelationships(AMMO_PORT_ROLE_ALT).isEmpty()));  
      return (!(schedule.getMatchingRelationships(AMMO_PORT_ROLE.getConverse()).isEmpty()) ||
        (!(schedule.getMatchingRelationships(AMMO_PORT_ROLE_ALT.getConverse()).isEmpty())));
    } else {
      return false;
    }
  }

  /** 
   * test if organization is a non-ammo port
   * @param p Organization to be tested
   * @return true if it is a generic port
   */
  public boolean isCargoPort(Asset p) {
    if (p instanceof Organization) {
      RelationshipSchedule schedule = ((Organization)p).getRelationshipSchedule(); 
      //return (schedule.getMatchingRelationships(CARGO_PORT_ROLE).size() > 0);
      return (!schedule.getMatchingRelationships(CARGO_PORT_ROLE.getConverse()).isEmpty());
    }         
    return false;
  }

  public String getUniqueTag(Asset a) {
    return new String(a.getTypeIdentificationPG().getTypeIdentification()+
          a.getItemIdentificationPG().getItemIdentification());
  }

  GLMPrepPhrase glmPrepHelper;
  GLMPreference glmPrefHelper;
  GLMMeasure measureHelper;
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.