/
com/planet_ink/coffee_mud/Abilities/
com/planet_ink/coffee_mud/Abilities/Common/
com/planet_ink/coffee_mud/Abilities/Diseases/
com/planet_ink/coffee_mud/Abilities/Druid/
com/planet_ink/coffee_mud/Abilities/Fighter/
com/planet_ink/coffee_mud/Abilities/Prayers/
com/planet_ink/coffee_mud/Abilities/Properties/
com/planet_ink/coffee_mud/Abilities/Skills/
com/planet_ink/coffee_mud/Abilities/Songs/
com/planet_ink/coffee_mud/Abilities/Spells/
com/planet_ink/coffee_mud/Abilities/Thief/
com/planet_ink/coffee_mud/Abilities/Traps/
com/planet_ink/coffee_mud/Areas/interfaces/
com/planet_ink/coffee_mud/Behaviors/
com/planet_ink/coffee_mud/Behaviors/interfaces/
com/planet_ink/coffee_mud/CharClasses/interfaces/
com/planet_ink/coffee_mud/Commands/
com/planet_ink/coffee_mud/Commands/interfaces/
com/planet_ink/coffee_mud/Exits/interfaces/
com/planet_ink/coffee_mud/Items/Armor/
com/planet_ink/coffee_mud/Items/Basic/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Software/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
com/planet_ink/coffee_mud/Locales/interfaces/
com/planet_ink/coffee_mud/MOBS/
com/planet_ink/coffee_mud/Races/
com/planet_ink/coffee_mud/Races/interfaces/
com/planet_ink/coffee_mud/WebMacros/
com/planet_ink/coffee_mud/WebMacros/interfaces/
com/planet_ink/coffee_mud/core/smtp/
com/planet_ink/coffee_mud/core/threads/
com/planet_ink/siplet/applet/
lib/
resources/fakedb/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
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.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 com.planet_ink.coffee_mud.Libraries.interfaces.*;

/*
Copyright 2007-2010 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.
*/
@SuppressWarnings("unchecked")
public class DefaultRoomnumberSet implements RoomnumberSet
{
    public DVector root=new DVector(2);
    public String ID(){return "DefaultRoomnumberSet";}
    public int compareTo(CMObject o){ return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o));}
    public CMObject newInstance(){try{return (CMObject)getClass().newInstance();}catch(Exception e){return new DefaultRoomnumberSet();}}
    public void initializeClass(){}
    public CMObject copyOf()
    {
        DefaultRoomnumberSet R=new DefaultRoomnumberSet();
        R.root=new DVector(2);
        CMIntegerGrouper CI=null;
        for(int r=0;r<root.size();r++)
        {
        	CI=((CMIntegerGrouper)root.elementAt(r,2));
            R.root.addElement(root.elementAt(r,1),CI==null?null:CI.copyOf());
        }
        return R;
    }
    public void add(RoomnumberSet set)
    {
    	CMIntegerGrouper his=null;
    	CMIntegerGrouper mine=null;
    	String arName=null;
    	for(Enumeration v=set.getAreaNames();v.hasMoreElements();)
    	{
    		arName=(String)v.nextElement();
    		his=set.getGrouper(arName);
    		mine=set.getGrouper(arName);
    		if(mine==null)
    		{
    			if(his!=null)
	    			mine=(CMIntegerGrouper)his.copyOf();
    			root.addElement(arName.toUpperCase(),mine);
    		}
    		else
    			mine.add(his);
    	}
    }
    
    public void remove(String str)
    {
        String areaName=str.toUpperCase().trim();
        if(areaName.length()==0) return;
        
        String theRest=null;
        long roomNum=-1;
        int x=areaName.indexOf("#");
        CMIntegerGrouper CI=null;
        if(x<=0)
        	CI=getGrouper(areaName);
        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))))
            {
                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<CMIntegerGrouper.NEXT_BITS) roomNum|=CMIntegerGrouper.GRID_FLAGL;
                }
            }
            else
            if(CMath.isInteger(theRest))
                roomNum=Integer.parseInt(theRest.substring(x+1).trim());
        }
        if(CI==null) return;
        CI.remove(roomNum);
        if(CI.roomCount()==0)
        	root.removeElement(areaName.toUpperCase());
    }
    
    public int roomCountAllAreas()
    {
    	int total=0;
    	CMIntegerGrouper CMI=null;
    	for(int i=0;i<root.size();i++)
    	{
            CMI=(CMIntegerGrouper)root.elementAt(i,2);
            if(CMI==null) 
            	total++;
            else
	            total+=CMI.roomCount();
    	}
    	return total;
    }
    
    public int roomCount(String areaName)
    {
        int x=areaName.indexOf("#");
        if(x>0)
            areaName=areaName.substring(0,x).toUpperCase();
        else
            areaName=areaName.toUpperCase();
        int start=0;
        int end=root.size()-1;
        int comp=-1;
        int mid=-1;
        while(start<=end)
        {
            mid=(end+start)/2;
            comp=areaName.compareTo((String)root.elementAt(mid,1));
            if(comp==0)
            {
                if(root.elementAt(mid,2)!=null)
                {
                	CMIntegerGrouper CMI=(CMIntegerGrouper)root.elementAt(mid,2);
                	if(CMI==null) return 1;
                    return CMI.roomCount();
                }
                return 0;
            }
            else
            if(comp<0)
                end=mid-1;
            else
                start=mid+1;
        }
        return 0;
    }
    
    public String random()
    {
    	int total=0;
    	CMIntegerGrouper CMI=null;
    	for(int i=0;i<root.size();i++)
    	{
            CMI=(CMIntegerGrouper)root.elementAt(i,2);
            if(CMI==null)
            	total++;
            else
	            total+=CMI.roomCount();
    	}
    	if(total<=0) return null;
    	int which=CMLib.dice().roll(1,total,-1);
    	total=0;
        String roomID=null;
    	for(int i=0;i<root.size();i++)
    	{
            CMI=(CMIntegerGrouper)root.elementAt(i,2);
            if(CMI==null)
            	total++;
            else
	    		total+=CMI.roomCount();
    		if(which<total)
    		{
    			roomID=(String)root.elementAt(i,1);
    			break;
    		}
    	}
    	if(roomID==null) return null;
    	if(CMI==null)
    	{
    		//Log.errOut("RNUMS","Unable to even select an integer group! Picked "+which+"/"+grandTotal);
    		return roomID;
    	}
		long selection=CMI.random();
		return convertRoomID(roomID,selection);
    }
    
    public int[] convertRoomID(long coded)
    {
		if(coded==-1) return null;
		int[] ids=new int[3];
		ids[1]=-1;
		ids[2]=-1;
		if(coded<=CMIntegerGrouper.NEXT_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);
		long mask2=mask<<15;
		ids[1]=(int)((coded&mask2)>>15);
		mask|=mask2;
		mask=mask<<30;
		ids[0]=(int)(((coded&mask)>>30)&(CMIntegerGrouper.NEXT_BITSL-CMIntegerGrouper.GRID_FLAGL));
		return ids;
    }
    public String convertRoomID(String prefix, long coded)
    {
		if(coded==-1) return prefix;
		if(coded<CMIntegerGrouper.NEXT_BITS)
			return prefix+"#"+coded;
		long mask=0;
		for(int i=0;i<15;i++) mask=(mask<<1)+1;
		long thirdID=coded&mask;
		long mask2=mask<<15;
		long secondID=(coded&mask2)>>15;
		mask|=mask2;
		mask=mask<<30;
		long firstID=(((coded&mask)>>30)&(CMIntegerGrouper.NEXT_BITSL-CMIntegerGrouper.GRID_FLAGL));
		return prefix+"#"+firstID+"#("+secondID+","+thirdID+")";
    }
    
    public Enumeration getAreaNames(){ return ((Vector)root.getDimensionVector(1).clone()).elements();}
    
    private boolean isGrouper(String areaName)
    {
    	areaName=areaName.toUpperCase();
        int start=0;
        int end=root.size()-1;
        int comp=-1;
        int mid=-1;
        while(start<=end)
        {
            mid=(end+start)/2;
            comp=areaName.compareTo((String)root.elementAt(mid,1));
            if(comp==0) return true;
            else
            if(comp<0)
                end=mid-1;
            else
                start=mid+1;
        }
        return false;
    }
    
    public CMIntegerGrouper getGrouper(String areaName)
    {
    	areaName=areaName.toUpperCase();
        int start=0;
        int end=root.size()-1;
        int comp=-1;
        int mid=-1;
        while(start<=end)
        {
            mid=(end+start)/2;
            comp=areaName.compareTo((String)root.elementAt(mid,1));
            if(comp==0)
            {
                if(root.elementAt(mid,2)!=null)
                    return ((CMIntegerGrouper)root.elementAt(mid,2));
                return null;
            }
            else
            if(comp<0)
                end=mid-1;
            else
                start=mid+1;
        }
        return null;
    }
    
    public boolean contains(String str)
    {
    	if(str==null) return false;
        String theRest=null;
        long roomNum=-1;
        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))))
            {
                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<CMIntegerGrouper.NEXT_BITS) roomNum|=CMIntegerGrouper.GRID_FLAGL;
                }
            }
            else
            if(CMath.isInteger(theRest))
                roomNum=Integer.parseInt(theRest.substring(x+1).trim());
        }
        
        CMIntegerGrouper myGrouper=getGrouper(str);
        if((origX<0)&&(myGrouper==null)&&(isGrouper(str)))
        	return true;
        if(myGrouper==null) return false;
        return myGrouper.contains(roomNum);
    }
    
    public String xml()
    {
        StringBuffer str=new StringBuffer("<AREAS>");
        for(int i=0;i<root.size();i++)
        {
            str.append("<AREA><ID>"+(String)root.elementAt(i,1)+"</ID>");
            if(root.elementAt(i,2)!=null)
                str.append("<NUMS>"+((CMIntegerGrouper)root.elementAt(i,2)).text()+"</NUMS>");
            str.append("</AREA>");
        }
        return str.toString()+"</AREAS>";
    }

    public void parseXML(String xml)
    {
        Vector V=CMLib.xml().parseAllXML(xml);
        if((V==null)||(V.size()==0)) return;
        Vector xV=CMLib.xml().getRealContentsFromPieces(V,"AREAS");
        root.clear();
        String ID=null;
        String NUMS=null;
        if((xV!=null)&&(xV.size()>0))
            for(int x=0;x<xV.size();x++)
            {
                XMLLibrary.XMLpiece ablk=(XMLLibrary.XMLpiece)xV.elementAt(x);
                if((ablk.tag.equalsIgnoreCase("AREA"))&&(ablk.contents!=null))
                {
                    ID=CMLib.xml().getValFromPieces(ablk.contents,"ID");
                    NUMS=CMLib.xml().getValFromPieces(ablk.contents,"NUMS");
                    if((NUMS!=null)&&(NUMS.length()>0))
                        root.addElement(ID,((CMIntegerGrouper)CMClass.getCommon("DefaultCMIntegerGrouper")).parseText(NUMS));
                    else
                        root.addElement(ID,null);
                }
            }
    }
    
    public void add(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))))
            {
                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<CMIntegerGrouper.NEXT_BITS) roomNum|=CMIntegerGrouper.GRID_FLAGL;
                }
            }
            else
            if(CMath.isInteger(theRest))
                roomNum=Integer.parseInt(theRest.substring(x+1).trim());
        }
        int start=0;
        int end=root.size()-1;
        int comp=-1;
        int mid=-1;
        int lastStart=0;
        int lastEnd=root.size()-1;
        while(start<=end)
        {
            mid=(end+start)/2;
            comp=areaName.compareTo((String)root.elementAt(mid,1));
            if(comp==0)
                break;
            else
            if(comp<0)
            {
                lastEnd=end;
                end=mid-1;
            }
            else
            {
                lastStart=start;
                start=mid+1;
            }
        }
        if(comp==0)
        {
            if(root.elementAt(mid,2)!=null)
                ((CMIntegerGrouper)root.elementAt(mid,2)).add(roomNum);
        }
        else
        {
            if(mid<0)
                root.addElement(areaName,((CMIntegerGrouper)CMClass.getCommon("DefaultCMIntegerGrouper")).add(roomNum));
            else
            {
                for(comp=lastStart;comp<=lastEnd;comp++)
                    if(areaName.compareTo((String)root.elementAt(comp,1))<0)
                    {
                        root.insertElementAt(comp,areaName,((CMIntegerGrouper)CMClass.getCommon("DefaultCMIntegerGrouper")).add(roomNum));
                        return;
                    }
                root.addElement(areaName,((CMIntegerGrouper)CMClass.getCommon("DefaultCMIntegerGrouper")).add(roomNum));
            }
        }
    }
    
    public Enumeration getRoomIDs(){return new RoomnumberSetEnumeration();}
    
    private class RoomnumberSetEnumeration implements Enumeration
    {
    	Enumeration areaNames=null;
    	String areaName=null;
    	long[] nums=null;
    	String nextID=null;
    	int n=0;
    	public RoomnumberSetEnumeration(){ areaNames=getAreaNames();}
    	public boolean hasMoreElements(){
    		if(nextID==null) getNextID();
    		return nextID!=null;
    	}
    	public Object nextElement(){
    		if(nextID==null) getNextID();
    		String next=nextID;
    		nextID=null;
    		return next;
    	}
    	private void getNextID()
    	{
    		if(nums==null)
    		{
    			nextID=null;
    			if((areaNames==null)||(!areaNames.hasMoreElements()))
    				return;
    			areaName=(String)areaNames.nextElement();
    			CMIntegerGrouper grp=getGrouper(areaName);
    			if(grp==null){ nextID=areaName; return;}
    			nums=grp.allRoomNums();
    			n=0;
    		}
    		if((nums==null)||(n>=nums.length))
    		{
    			nums=null;
    			getNextID();
    			return;
    		}
    		long num=nums[n++];
    		nextID=convertRoomID(areaName,num);
    	}
    }
}