package com.planet_ink.coffee_mud.Common; import com.planet_ink.coffee_mud.core.interfaces.*; import com.planet_ink.coffee_mud.core.*; import com.planet_ink.coffee_mud.core.collections.*; import com.planet_ink.coffee_mud.Abilities.interfaces.*; import com.planet_ink.coffee_mud.Areas.interfaces.*; import com.planet_ink.coffee_mud.Behaviors.interfaces.*; import com.planet_ink.coffee_mud.CharClasses.interfaces.*; import com.planet_ink.coffee_mud.Commands.interfaces.*; import com.planet_ink.coffee_mud.Common.interfaces.*; import com.planet_ink.coffee_mud.Exits.interfaces.*; import com.planet_ink.coffee_mud.Items.interfaces.*; import com.planet_ink.coffee_mud.Locales.interfaces.*; import com.planet_ink.coffee_mud.MOBS.interfaces.*; import com.planet_ink.coffee_mud.Races.interfaces.*; import java.util.*; import java.util.Map.Entry; import com.planet_ink.coffee_mud.Libraries.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.XMLLibrary.XMLTag; /* Copyright 2005-2019 Bo Zimmerman 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. */ public class DefaultRoomnumberSet implements RoomnumberSet { @Override public String ID() { return "DefaultRoomnumberSet"; } @Override public String name() { return ID(); } public STreeMap<String,LongSet> root=new STreeMap<String,LongSet>(); @Override public int compareTo(final CMObject o) { return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o)); } @Override public CMObject newInstance() { try { return getClass().newInstance(); } catch(final Exception e) { return new DefaultRoomnumberSet(); } } @Override public void initializeClass() { } @Override public CMObject copyOf() { final DefaultRoomnumberSet R=new DefaultRoomnumberSet(); R.root=new STreeMap<String,LongSet>(); LongSet CI=null; for(final String area : root.keySet()) { CI=root.get(area); if(CI == null) R.root.put(area,null); else R.root.put(area,CI.copyOf()); } return R; } @Override public synchronized void add(final RoomnumberSet set) { LongSet his=null; LongSet mine=null; String arName=null; for(final Iterator<String> v=set.getAreaNames();v.hasNext();) { arName=v.next(); his=set.getGrouper(arName); mine=set.getGrouper(arName); if(mine==null) { if(his!=null) mine=his.copyOf(); root.put(arName.toUpperCase(),mine); } else mine.add(his); } } @Override public synchronized void remove(final String str) { String areaName=str.toUpperCase().trim(); if(areaName.length()==0) return; String theRest=null; long roomNum=-1; int x=areaName.indexOf('#'); LongSet CI=null; if(x<=0) { CI=getGrouper(areaName); if(CI!=null) { root.remove(areaName); return; } } else if(x>0) { theRest=areaName.substring(x+1).trim(); areaName=areaName.substring(0,x); CI=getGrouper(areaName); if(CI==null) return; x=theRest.indexOf("#("); if((x>=0)&&(theRest.endsWith(")"))&&(CMath.isInteger(theRest.substring(0,x)))) { final int comma=theRest.indexOf(",",x); if(comma>0) { roomNum=(Long.parseLong(theRest.substring(0,x))<<30); roomNum+=(Long.parseLong(theRest.substring(x+2,comma))<<15); roomNum+=Long.parseLong(theRest.substring(comma+1,theRest.length()-1)); if(roomNum<LongSet.INT_BITS) roomNum|=LongSet.OPTION_FLAG_LONG; } } else if(CMath.isInteger(theRest)) roomNum=Integer.parseInt(theRest.substring(x+1).trim()); } if(CI==null) return; CI.remove(Long.valueOf(roomNum)); if(CI.size()==0) root.remove(areaName.toUpperCase()); } @Override public int roomCountAllAreas() { int total=0; for(final LongSet CMI : root.values()) { if(CMI==null) total++; else total+=CMI.size(); } return total; } @Override public boolean isEmpty() { if(!root.isEmpty()) { for(final LongSet CMI : root.values()) { if((CMI==null) ||(!CMI.isEmpty())) return false; } } return true; } @Override public int roomCount(String areaName) { final int x=areaName.indexOf('#'); if(x>0) areaName=areaName.substring(0,x).toUpperCase(); else areaName=areaName.toUpperCase(); final LongSet CMI=root.get(areaName); if(CMI!=null) return CMI.size(); return 0; } @Override public String random() { int total=roomCountAllAreas(); if(total<=0) return null; final int which=CMLib.dice().roll(1,total,-1); total=0; String roomID=null; LongSet CMI = null; for(final Entry<String,LongSet> set : root.entrySet()) { CMI=set.getValue(); if(CMI==null) total++; else total+=CMI.size(); if(which<total) { roomID=set.getKey(); break; } } if(roomID==null) return null; if(CMI==null) { //Log.errOut("RNUMS","Unable to even select an integer group! Picked "+which+"/"+grandTotal); return roomID; } final long selection=CMI.getRandom(); return convertRoomID(roomID,selection); } public int[] convertRoomID(final long coded) { if(coded==-1) return null; final int[] ids=new int[3]; ids[1]=-1; ids[2]=-1; if(coded<=LongSet.INT_BITS) { ids[0]=(int)coded; return ids; } long mask=0; for(int i=0;i<15;i++) mask=(mask<<1)+1; ids[2]=(int)(coded&mask); final long mask2=mask<<15; ids[1]=(int)((coded&mask2)>>15); mask|=mask2; mask=mask<<30; ids[0]=(int)(((coded&mask)>>30)&(LongSet.LONG_BITS-LongSet.OPTION_FLAG_LONG)); return ids; } public String convertRoomID(final String prefix, final long coded) { if(coded==-1) return prefix; if(coded<LongSet.INT_BITS) return prefix+"#"+coded; long mask=0; for(int i=0;i<15;i++) mask=(mask<<1)+1; final long thirdID=coded&mask; final long mask2=mask<<15; final long secondID=(coded&mask2)>>15; mask|=mask2; mask=mask<<30; final long firstID=(((coded&mask)>>30)&(LongSet.LONG_BITS-LongSet.OPTION_FLAG_LONG)); return prefix+"#"+firstID+"#("+secondID+","+thirdID+")"; } @Override public Iterator<String> getAreaNames() { return root.keySet().iterator(); } private boolean isGrouper(final String areaName) { return root.containsKey(areaName.toUpperCase()); } @Override public LongSet getGrouper(final String areaName) { return root.get(areaName.toUpperCase()); } @Override public boolean contains(String str) { if(str==null) return false; String theRest=null; long roomNum=0; final int origX=str.indexOf('#'); int x=origX; if(x>0) { theRest=str.substring(x+1).trim(); str=str.substring(0,x); x=theRest.indexOf("#("); if((x>=0)&&(theRest.endsWith(")"))&&(CMath.isInteger(theRest.substring(0,x)))) { final int comma=theRest.indexOf(",",x); if(comma>0) { roomNum=Long.parseLong(theRest.substring(0,x))<<30; roomNum+=(Long.parseLong(theRest.substring(x+2,comma))<<15); roomNum+=Long.parseLong(theRest.substring(comma+1,theRest.length()-1)); if(roomNum<LongSet.INT_BITS) roomNum|=LongSet.OPTION_FLAG_LONG; } } else if(CMath.isInteger(theRest)) roomNum=Integer.parseInt(theRest.substring(x+1).trim()); } final LongSet myGrouper=getGrouper(str); if((origX<0)&&(myGrouper==null)&&(isGrouper(str))) return true; if(myGrouper==null) return false; return myGrouper.contains(roomNum); } @Override public String xml() { final StringBuffer str=new StringBuffer("<AREAS>"); for(final Entry<String,LongSet> set : root.entrySet()) { str.append("<AREA><ID>"+set.getKey()+"</ID>"); if(set.getValue()!=null) str.append("<NUMS>"+set.getValue().toString()+"</NUMS>"); str.append("</AREA>"); } return str.toString()+"</AREAS>"; } @Override public void parseXML(final String xml) { final List<XMLLibrary.XMLTag> V=CMLib.xml().parseAllXML(xml); if((V==null)||(V.size()==0)) return; final List<XMLLibrary.XMLTag> xV=CMLib.xml().getContentsFromPieces(V,"AREAS"); root.clear(); String ID=null; String NUMS=null; if((xV!=null)&&(xV.size()>0)) { for(int x=0;x<xV.size();x++) { final XMLTag ablk=xV.get(x); if((ablk.tag().equalsIgnoreCase("AREA"))&&(ablk.contents()!=null)) { ID=ablk.getValFromPieces("ID").toUpperCase(); NUMS=ablk.getValFromPieces("NUMS"); if((NUMS!=null)&&(NUMS.length()>0)) root.put(ID,new LongSet().parseString(NUMS)); else root.put(ID,null); } } } } @Override public synchronized void add(final String str) { String areaName=str.toUpperCase().trim(); if(areaName.length()==0) return; String theRest=null; long roomNum=-1; int x=areaName.indexOf('#'); if(x>0) { theRest=areaName.substring(x+1).trim(); areaName=areaName.substring(0,x); x=theRest.indexOf("#("); if((x>=0)&&(theRest.endsWith(")"))&&(CMath.isInteger(theRest.substring(0,x)))) { final int comma=theRest.indexOf(",",x); if(comma>0) { roomNum=(Long.parseLong(theRest.substring(0,x))<<30); roomNum+=(Long.parseLong(theRest.substring(x+2,comma))<<15); roomNum+=Long.parseLong(theRest.substring(comma+1,theRest.length()-1)); if(roomNum<LongSet.INT_BITS) roomNum|=LongSet.OPTION_FLAG_LONG; } } else if(CMath.isInteger(theRest)) roomNum=Integer.parseInt(theRest.substring(x+1).trim()); } else if(!str.equals("START")) { Log.debugOut("Attempt to add non-numbered room "+str+" to "+areaName); Log.debugOut(new Exception()); } LongSet CI = root.get(areaName); if(CI==null) { if(roomNum>=0) CI=new LongSet(); root.put(areaName,CI); } if((CI!=null)&&(roomNum>=0)) { CI.add(Long.valueOf(roomNum)); } } @Override public Enumeration<String> getRoomIDs() { return new RoomnumberSetEnumeration(); } private class RoomnumberSetEnumeration implements Enumeration<String> { Iterator<String> areaNames=null; String areaName=null; long[] nums=null; String nextID=null; int n=0; public RoomnumberSetEnumeration() { areaNames = getAreaNames(); } @Override public boolean hasMoreElements() { if(nextID==null) getNextID(); return nextID!=null; } @Override public String nextElement() { if(nextID==null) getNextID(); final String next=nextID; nextID=null; return next; } private void getNextID() { if(nums==null) { nextID=null; if((areaNames==null)||(!areaNames.hasNext())) return; areaName=areaNames.next(); final LongSet grp=getGrouper(areaName); if(grp==null) { nextID=areaName; return; } nums=grp.getAllNumbers(); n=0; } if((nums==null)||(n>=nums.length)) { nums=null; getNextID(); return; } final long num=nums[n++]; nextID=convertRoomID(areaName,num); } } }