/* * JaamSim Discrete Event Simulation * Copyright (C) 2011 Ausenco Engineering Canada Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jaamsim.input; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import com.jaamsim.basicsim.Entity; /** * Class KeyListInput for storing a list of entities of class V, with an optional key of class K1 */ public class KeyListInput<K1 extends Entity, V extends Entity> extends ListInput<ArrayList<V>> { private Class<K1> keyClass; private Class<V> valClass; private HashMap<K1,ArrayList<V>> hashMap; private ArrayList<V> noKeyValue; // the value when there is no key public KeyListInput(Class<K1> kClass, Class<V> vClass, String keyword, String cat, ArrayList<V> def) { super(keyword, cat, def); keyClass = kClass; valClass = vClass; hashMap = new HashMap<>(); noKeyValue = def; } @SuppressWarnings("unchecked") @Override public void copyFrom(Input<?> in) { super.copyFrom(in); KeyListInput<K1, V> inp = (KeyListInput<K1, V>) in; hashMap = inp.hashMap; noKeyValue = inp.noKeyValue; } @Override public void parse(KeywordIndex kw) throws InputErrorException { for (KeywordIndex each : kw.getSubArgs()) this.innerParse(each); } private void innerParse(KeywordIndex kw) { ArrayList<String> input = new ArrayList<>(kw.numArgs()); for (int i = 0; i < kw.numArgs(); i++) input.add(kw.getArg(i)); ArrayList<K1> list; try { // Determine the key(s) list = Input.parseEntityList(input.subList(0, 1), keyClass, true); } catch (InputErrorException e) { // A key was not provided. Set the "no key" value // If adding to the list // The input is of the form: ++ <value1 value2 value3...> if( kw.getArg( 0 ).equals( "++" ) ) { ArrayList<V> newNoKeyValue; if( noKeyValue == null ) newNoKeyValue = new ArrayList<>(); else newNoKeyValue = new ArrayList<>( noKeyValue ); ArrayList<V> addedValues = Input.parseEntityList( input.subList(1,input.size()), valClass, true ); for( V val : addedValues ) { if( newNoKeyValue.contains( val ) ) throw new InputErrorException(INP_ERR_NOTUNIQUE, val.getName()); newNoKeyValue.add( val ); } noKeyValue = newNoKeyValue; } // If removing from the list // The input is of the form: -- <value1 value2 value3...> else if( kw.getArg( 0 ).equals( "--" ) ) { ArrayList<V> removedValues = Input.parseEntityList( input.subList(1,input.size()), valClass, true ); for( V val : removedValues ) { if( ! noKeyValue.contains( val ) ) InputAgent.logWarning( "Could not remove " + val + " from " + this.getKeyword() ); noKeyValue.remove( val ); } } // Otherwise, just set the list normally // The input is of the form: <value1 value2 value3...> else { noKeyValue = Input.parseEntityList( input, valClass, true ); } return; } // If adding to the list // The input is of the form: <Key> ++ <value1 value2 value3...> if( kw.getArg( 1 ).equals( "++" ) ) { // Set the value for the given keys for( int i = 0; i < list.size(); i++ ) { ArrayList<V> values; if( hashMap.get( list.get( i ) ) == null ) values = new ArrayList<>(); else values = new ArrayList<>( hashMap.get( list.get( i ) ) ); ArrayList<V> addedValues = Input.parseEntityList( input.subList(2,input.size()), valClass, true ); for( V val : addedValues ) { if( values.contains( val ) ) throw new InputErrorException(INP_ERR_NOTUNIQUE, val.getName()); values.add( val ); } hashMap.put( list.get(i), values ); } } // If removing from the list // The input is of the form: <Key> -- <value1 value2 value3...> else if( kw.getArg( 1 ).equals( "--" ) ) { // Set the value for the given keys for( int i = 0; i < list.size(); i++ ) { ArrayList<V> values = new ArrayList<>( hashMap.get( list.get( i ) ) ); ArrayList<V> removedValues = Input.parseEntityList( input.subList(2,input.size()), valClass, true ); for( V val : removedValues ) { if( ! values.contains( val ) ) InputAgent.logWarning( "Could not remove " + val + " from " + this.getKeyword() ); values.remove( val ); } hashMap.put( list.get(i), values ); } } // Otherwise, just set the list normally // The input is of the form: <Key> <value1 value2 value3...> else { // Determine the value ArrayList<V> val = Input.parseEntityList( input.subList(1,input.size()), valClass, true ); // Set the value for the given keys for( int i = 0; i < list.size(); i++ ) { hashMap.put( list.get(i), val ); } } } @Override public void setTokens(KeywordIndex kw) { isDef = false; String[] args = kw.getArgArray(); // If there are previous inputs and existing or new keys if (args.length > 0) { if (valueTokens != null && hashMap.keySet().size() > 0) { this.appendTokens(args); return; } } // Consider the following input cases: // Object1 Keyword1 { Key1 ++ Entity1 ... // Object1 Keyword1 { { Key1 ++ Entity1 ... if (args.length >= 3) { if (args[1].equals( "++" ) || args[1].equals( "--" ) || args[2].equals( "++" ) || args[2].equals( "--" )) { this.appendTokens(args); return; } } valueTokens = args; } @Override public ArrayList<V> getValue() { return null; } public ArrayList<V> getValueFor( K1 k1 ) { ArrayList<V> val = hashMap.get( k1 ); if( val == null ) { return noKeyValue; } else { return val; } } @Override public String getDefaultString() { if (defValue == null) return ""; if (defValue.size() == 0) return ""; StringBuilder tmp = new StringBuilder(defValue.get(0).getName()); for (int i = 1; i < defValue.size(); i++) { tmp.append(SEPARATOR); tmp.append(defValue.get(i).getName()); } return tmp.toString(); } @Override public void reset() { super.reset(); hashMap.clear(); noKeyValue = this.getDefaultValue(); } @Override public int getListSize() { // TODO Auto-generated method stub return 0; } @Override public ArrayList<String> getValidOptions() { ArrayList<String> list = new ArrayList<>(); for(V each: Entity.getClonesOfIterator(valClass) ) { if(each.testFlag(Entity.FLAG_GENERATED)) continue; list.add(each.getName()); } Collections.sort(list, Input.uiSortOrder); return list; } @Override public String toString() { return String.format("%s %s", noKeyValue, hashMap); } public ArrayList<K1> getAllKeys() { ArrayList<K1> keys = new ArrayList<>(); for (K1 each : hashMap.keySet()) { keys.add(each); } return keys; } }