/
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/Languages/
com/planet_ink/coffee_mud/Abilities/Misc/
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/Behaviors/
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/Common/
com/planet_ink/coffee_mud/Common/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/CompTech/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Items/interfaces/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
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/
com/planet_ink/coffee_mud/core/collections/
com/planet_ink/coffee_mud/core/interfaces/
com/planet_ink/coffee_mud/core/intermud/
com/planet_ink/coffee_mud/core/intermud/i3/
com/planet_ink/coffee_web/server/
com/planet_ink/siplet/applet/
lib/
resources/factions/
resources/fakedb/
resources/progs/autoplayer/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/clan.templates/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
web/pub/textedit/
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.Common.interfaces.Law.TreasurySet;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

/*
   Copyright 2005-2016 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 DefaultLawSet implements Law
{
	@Override public String ID(){return "DefaultLawSet";}
	@Override public String name() { return ID();}
	@Override public CMObject newInstance(){try{return getClass().newInstance();}catch(final Exception e){return new DefaultLawSet();}}
	@Override public void initializeClass(){}
	@Override public int compareTo(CMObject o){ return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o));}
	@Override
	public CMObject copyOf()
	{
		try
		{
			return (DefaultLawSet)this.clone();
		}
		catch(final CloneNotSupportedException e)
		{
			return newInstance();
		}
	}

	private boolean namesModifiable=false;
	private boolean lawsModifiable=false;
	private LegalBehavior legalDetails=null;

	private final List<List<String>>	otherCrimes=new Vector<List<String>>();
	private final List<String[]> 		otherBits=new Vector<String[]>();
	private final List<List<String>> 	bannedSubstances=new Vector<List<String>>();
	private final List<String[]> 		bannedBits=new Vector<String[]>();
	private final Map<String,String[]>	abilityCrimes=new Hashtable<String,String[]>();
	private final Map<String,String[]>	basicCrimes=new Hashtable<String,String[]>();
	private final Map<String, Object>	taxLaws=new Hashtable<String, Object>();

	private List<String> chitChat=new Vector<String>();
	private List<String> chitChat2=new Vector<String>();
	private List<String> chitChat3=new Vector<String>();
	private List<String> jailRooms=new Vector<String>();
	private List<String> releaseRooms=new Vector<String>();
	private List<String> officerNames=new Vector<String>();
	private List<String> judgeNames=new Vector<String>();
	private String[] 	 messages=new String[Law.MSG_TOTAL];

	private boolean activated=true;

	private final SVector<LegalWarrant> oldWarrants=new SVector<LegalWarrant>();
	private final SVector<LegalWarrant> warrants=new SVector<LegalWarrant>();

	private boolean arrestMobs=false;

	private Properties theLaws=null;
	private int lastMonthChecked=-1;

	private final String[] paroleMessages=new String[4];
	private final Integer[] paroleTimes=new Integer[4];

	private final String[] jailMessages=new String[4];
	private final Integer[] jailTimes=new Integer[4];

	@Override
	public void initialize(LegalBehavior details, Properties laws, boolean modifiableNames, boolean modifiableLaws)
	{
		legalDetails=details;
		namesModifiable=modifiableNames;
		lawsModifiable=modifiableLaws;
		resetLaw(laws);
	}

	@Override 
	public List<List<String>> otherCrimes() 
	{ 
		return otherCrimes;
	}
	
	@Override 
	public List<String[]> otherBits() 
	{ 
		return otherBits;
	}
	
	@Override 
	public List<List<String>> bannedSubstances() 
	{ 
		return bannedSubstances;
	}
	
	@Override 
	public List<String[]> bannedBits() 
	{ 
		return bannedBits;
	}
	
	@Override 
	public Map<String,String[]> abilityCrimes()
	{ 
		return abilityCrimes;
	}
	
	@Override 
	public Map<String,String[]> basicCrimes()
	{ 
		return basicCrimes;
	}
	
	@Override 
	public Map<String, Object> taxLaws()
	{
		return taxLaws;
	}

	@Override
	public boolean hasModifiableNames()
	{
		return namesModifiable;
	}
	
	@Override 
	public boolean hasModifiableLaws()
	{
		return lawsModifiable;
	}

	@Override 
	public List<String> chitChat()
	{ 
		return chitChat;
	}
	
	@Override 
	public List<String> chitChat2()
	{ 
		return chitChat2;
	}
	
	@Override 
	public List<String> chitChat3()
	{ 
		return chitChat3;
	}
	
	@Override 
	public List<String> jailRooms()
	{ 
		return jailRooms;
	}
	
	@Override 
	public List<String> releaseRooms()
	{ 
		return releaseRooms;
	}
	
	@Override 
	public List<String> officerNames()
	{ 
		return officerNames;
	}
	
	@Override 
	public List<String> judgeNames()
	{ 
		return judgeNames;
	}
	
	@Override 
	public String[] messages()
	{ 
		return messages;
	}

	@Override 
	public List<LegalWarrant> oldWarrants()
	{ 
		return oldWarrants;
	}
	
	@Override 
	public List<LegalWarrant> warrants()
	{ 
		return warrants;
	}

	@Override public boolean arrestMobs()
	{ 
		return arrestMobs;
	}

	@Override 
	public String[] paroleMessages()
	{ 
		return paroleMessages;
	}
	
	@Override 
	public Integer[] paroleTimes()
	{ 
		return paroleTimes;
	}

	@Override 
	public String[] jailMessages()
	{ 
		return jailMessages;
	}
	
	@Override 
	public Integer[] jailTimes()
	{ 
		return jailTimes;
	}

	@Override
	public void changeStates(LegalWarrant W, int state)
	{
		if((W==null)||(W.criminal()==null))
			return;
		if(warrants.contains(W))
			for(int w=0;w<warrants.size();w++)
			{
				final LegalWarrant W2=warrants.elementAt(w);
				if(W2.criminal()==W.criminal())
					W2.setState(state);
			}
	}

	@Override
	public TreasurySet getTreasuryNSafe(Area A)
	{
		Room treasuryR=null;
		Container container=null;
		final String tres=(String)taxLaws().get("TREASURY");
		Item I=null;
		if((tres!=null)&&(tres.length()>0))
		{
			final List<String> V=CMParms.parseSemicolons(tres,false);
			if(V.size()>0)
			{
				Room R=null;
				final String room=V.get(0);
				String item="";
				if(V.size()>1)
					item=CMParms.combine(V,1);
				if(!room.equalsIgnoreCase("*"))
				{
					treasuryR=CMLib.map().getRoom(room);
					if(treasuryR!=null)
					{
						I=treasuryR.findItem(item);
						if(I instanceof Container)
						container=(Container)I;
					}
				}
				else
				if(item.length()>0)
				for(final Enumeration<Room> e=A.getMetroMap();e.hasMoreElements();)
				{
					R=e.nextElement();
					I=R.findItem(item);
					if(I instanceof Container)
					{
						container=(Container)I;
						treasuryR=R;
						break;
					}
				}
				if((room.length()>0)&&(treasuryR==null))
					treasuryR=A.getRandomMetroRoom();
			}
		}
		return new Law.TreasurySet(treasuryR,container);
	}

	@Override
	public void propertyTaxTick(Area A, boolean debugging)
	{
		if(lastMonthChecked!=A.getTimeObj().getMonth())
		{
			lastMonthChecked=A.getTimeObj().getMonth();
			double tax=CMath.s_double((String)taxLaws.get("PROPERTYTAX"));
			if(tax==0.0)
				return;
			tax=CMath.div(tax,100.0);
			List<LandTitle> titles=CMLib.law().getAllUniqueLandTitles(A.getMetroMap(),"*",false);
			final Hashtable<String,Vector<LandTitle>> owners=new Hashtable<String,Vector<LandTitle>>();
			for(final LandTitle T : titles)
			{
				Vector<LandTitle> D=owners.get(T.getOwnerName());
				if(D==null)
				{
					D=new Vector<LandTitle>();
					owners.put(T.getOwnerName(),D);
				}
				D.addElement(T);
			}
			titles=null;
			final Law.TreasurySet treas=getTreasuryNSafe(A);
			final Room treasuryR=treas.room;
			final Container container=treas.container;
			final String[] evasionBits=(String[])taxLaws().get("TAXEVASION");

			for(final String owner : owners.keySet())
			{
				MOB responsibleMob=null;
				final Clan C=CMLib.clans().getClan(owner);
				if(C!=null)
					responsibleMob=C.getResponsibleMember();
				else
					responsibleMob=CMLib.players().getLoadPlayer(owner);
				final Vector<LandTitle> particulars=owners.get(owner);

				double totalValue=0;
				double paid=0;
				double owed=0;
				final StringBuffer properties=new StringBuffer("");
				LandTitle T=null;
				List<Room> propertyRooms=null;

				for(int p=0;p<particulars.size();p++)
				{
					if(p>0)
						properties.append(", ");
					T=(particulars.elementAt(p));
					propertyRooms=T.getAllTitledRooms();
					if((propertyRooms.size()<2)
					||(CMLib.map().getArea(T.landPropertyID())!=null))
						properties.append(T.landPropertyID());
					else
						properties.append("around "+CMLib.map().getExtendedRoomID(propertyRooms.get(0)));
					totalValue+=T.getPrice();
					if(T.backTaxes()>0)
					{
						totalValue+=T.backTaxes();
						owed+=T.backTaxes();
					}
				}
				owed+=CMath.mul(totalValue,tax);

				if(owed>0)
				for(int p=0;p<particulars.size();p++)
				{
					T=(particulars.elementAt(p));
					if(T.backTaxes()<0)
					{
						if((-T.backTaxes())>=owed)
						{
							paid+=owed;
							T.setBackTaxes((int)Math.round((T.backTaxes())+owed));
							T.updateTitle();
							break;
						}
						paid+=(-T.backTaxes());
						T.setBackTaxes(0);
						T.updateTitle();
					}
				}
				if(owed>0)
				{
					owed-=paid;
					if((owed>0)&&(!CMLib.beanCounter().modifyLocalBankGold(A,
									owner,
									CMLib.utensils().getFormattedDate(A)+": Withdrawal of "+owed+": Taxes on property: "+properties.toString(),
									CMLib.beanCounter().getCurrency(A),
								   -owed)))
					{
						boolean owesButNotConfiscated=false;
						for(int p=0;p<particulars.size();p++)
						{
							T=particulars.elementAt(p);
							double owedOnThisLand=CMath.mul(T.getPrice(),tax);
							owedOnThisLand-=(paid/particulars.size());
							if(owedOnThisLand>0)
							{
								T.setBackTaxes((int)Math.round((T.backTaxes())+owedOnThisLand));
								if((T.getPrice()/T.backTaxes())<4)
								{
									final Clan clanC=CMLib.clans().getClan(T.getOwnerName());
									if(clanC!=null)
									{
										final List<Pair<Clan,Integer>> clanSet=new Vector<Pair<Clan,Integer>>();
										clanSet.add(new Pair<Clan,Integer>(C,Integer.valueOf(0)));
										final List<String> channels=CMLib.channels().getFlaggedChannelNames(ChannelsLibrary.ChannelFlag.CLANINFO);
										for(int i=0;i<channels.size();i++)
											CMLib.commands().postChannel(channels.get(i),clanSet,CMLib.lang().L("@x1 has lost the title to @x2 due to failure to pay property taxes.",T.getOwnerName(),T.landPropertyID()),false);
									}
									else
									if(CMLib.players().getPlayer(T.getOwnerName())!=null)
										CMLib.players().getPlayer(T.getOwnerName()).tell(CMLib.lang().L("You have lost the title to @x1 due to failure to pay property taxes.",T.landPropertyID()));
									T.setOwnerName("");
									T.updateTitle();
								}
								else
								{
									owesButNotConfiscated=true;
									T.updateTitle();
								}
							}
						}
						if((owesButNotConfiscated)
						&&(evasionBits!=null)
						&&(evasionBits[Law.BIT_CRIMENAME].length()>0)
						&&(responsibleMob!=null))
						{
							legalDetails.fillOutWarrant(responsibleMob,
													   this,
													   A,
													   null,
													   evasionBits[Law.BIT_CRIMELOCS],
													   evasionBits[Law.BIT_CRIMEFLAGS],
													   evasionBits[Law.BIT_CRIMENAME],
													   evasionBits[Law.BIT_SENTENCE],
													   evasionBits[Law.BIT_WARNMSG]);
						}
					}
					else
					{
						for(int p=0;p<particulars.size();p++)
						{
							T=particulars.elementAt(p);
							if(T.backTaxes()>0)
							{
								T.setBackTaxes(0);
								T.updateTitle();
							}
						}
						if(owed<0)
							owed=0;
						if((treasuryR!=null)&&((owed+paid)>0))
						{
							final List<Coins> V=CMLib.beanCounter().makeAllCurrency(CMLib.beanCounter().getCurrency(A),owed+paid);
							for(int v=0;v<V.size();v++)
							{
								final Coins COIN=V.get(v);
								COIN.setContainer(container);
								treasuryR.addItem(COIN);
								COIN.putCoinsBack();
							}
						}
						if((evasionBits!=null)
						&&(evasionBits[Law.BIT_CRIMENAME].length()>0)
						&&(responsibleMob!=null))
							while(getWarrant(responsibleMob,evasionBits[Law.BIT_CRIMENAME],true,debugging)!=null)
								{}
					}
				}
			}

		}
	}

	@Override
	public String getMessage(int which)
	{
		if((which>=0)&&(which<messages.length)&&(messages[which]!=null))
			return messages[which];
		return "";
	}
	@Override
	public String paroleMessages(int which)
	{
		if((which>=0)
		&&(which<paroleMessages.length)
		&&(paroleMessages[which]!=null))
			return paroleMessages[which];
		return "";
	}
	@Override
	public int paroleTimes(int which)
	{
		if((which>=0)
		&&(which<paroleTimes.length)
		&&(paroleTimes[which]!=null))
			return paroleTimes[which].intValue();
		return 0;
	}
	@Override
	public String jailMessages(int which)
	{
		if((which>=0)
		&&(which<jailMessages.length)
		&&(jailMessages[which]!=null))
			return jailMessages[which];
		return "";
	}
	@Override
	public int jailTimes(int which)
	{
		if((which>=0)
		&&(which<jailTimes.length)
		&&(jailTimes[which]!=null))
			return jailTimes[which].intValue();
		return 0;
	}

	@Override
	public String getInternalStr(String msg)
	{
		if((theLaws!=null)&&(theLaws.get(msg)!=null))
			return (String)theLaws.get(msg);
		return "";
	}
	@Override
	public boolean isInternalStr(String msg)
	{
		if((theLaws!=null)&&(theLaws.get(msg)!=null))
			return true;
		return false;
	}
	@Override
	public void setInternalStr(String tag, String value)
	{
		if(theLaws!=null)
		{
			if(theLaws.get(tag)!=null)
				theLaws.remove(tag);
			theLaws.put(tag,value);
		}
	}
	@Override 
	public boolean lawIsActivated()
	{ 
		return activated;
	}

	@Override
	public void resetLaw()
	{
		if(theLaws!=null)
			resetLaw(theLaws);
	}
	private void resetLaw(Properties laws)
	{
		theLaws=laws;
		activated=(!getInternalStr("ACTIVATED").equalsIgnoreCase("FALSE"));
		officerNames=CMParms.parse(getInternalStr("OFFICERS"));
		chitChat=CMParms.parse(getInternalStr("CHITCHAT"));
		chitChat2=CMParms.parse(getInternalStr("CHITCHAT2"));
		chitChat3=CMParms.parse(getInternalStr("CHITCHAT3"));
		judgeNames=CMParms.parse(getInternalStr("JUDGE"));

		arrestMobs=getInternalStr("ARRESTMOBS").equalsIgnoreCase("true");

		messages=new String[Law.MSG_TOTAL];
		messages[Law.MSG_PREVOFF]=getInternalStr("PREVOFFMSG");
		messages[Law.MSG_WARNING]=getInternalStr("WARNINGMSG");
		messages[Law.MSG_THREAT]=getInternalStr("THREATMSG");
		messages[Law.MSG_EXECUTE]=getInternalStr("EXECUTEMSG");
		messages[Law.MSG_COPKILLER]=isInternalStr("COPKILLERMSG")?getInternalStr("COPKILLERMSG"):"COPKILLER!!!! ARGH!!!!!!";
		messages[Law.MSG_PROTECTEDMASK]=getInternalStr("PROTECTED");
		messages[Law.MSG_TRESPASSERMASK]=getInternalStr("TRESPASSERS");
		messages[Law.MSG_RESISTFIGHT]=getInternalStr("RESISTFIGHTMSG");
		messages[Law.MSG_NORESIST]=getInternalStr("NORESISTMSG");
		messages[Law.MSG_RESISTWARN]=getInternalStr("RESISTWARNMSG");
		messages[Law.MSG_PAROLEDISMISS]=getInternalStr("PAROLEDISMISS");
		messages[Law.MSG_RESIST]=getInternalStr("RESISTMSG");
		messages[Law.MSG_LAWFREE]=getInternalStr("LAWFREE");

		paroleMessages[0]=getInternalStr("PAROLE1MSG");
		paroleMessages[1]=getInternalStr("PAROLE2MSG");
		paroleMessages[2]=getInternalStr("PAROLE3MSG");
		paroleMessages[3]=getInternalStr("PAROLE4MSG");
		paroleTimes[0]=Integer.valueOf(CMath.s_int(getInternalStr("PAROLE1TIME")));
		paroleTimes[1]=Integer.valueOf(CMath.s_int(getInternalStr("PAROLE2TIME")));
		paroleTimes[2]=Integer.valueOf(CMath.s_int(getInternalStr("PAROLE3TIME")));
		paroleTimes[3]=Integer.valueOf(CMath.s_int(getInternalStr("PAROLE4TIME")));

		jailMessages[0]=getInternalStr("JAIL1MSG");
		jailMessages[1]=getInternalStr("JAIL2MSG");
		jailMessages[2]=getInternalStr("JAIL3MSG");
		jailMessages[3]=getInternalStr("JAIL4MSG");
		jailTimes[0]=Integer.valueOf(CMath.s_int(getInternalStr("JAIL1TIME")));
		jailTimes[1]=Integer.valueOf(CMath.s_int(getInternalStr("JAIL2TIME")));
		jailTimes[2]=Integer.valueOf(CMath.s_int(getInternalStr("JAIL3TIME")));
		jailTimes[3]=Integer.valueOf(CMath.s_int(getInternalStr("JAIL4TIME")));

		jailRooms=CMParms.parseSemicolons(getInternalStr("JAIL"),true);
		releaseRooms=CMParms.parseSemicolons(getInternalStr("RELEASEROOM"),true);

		taxLaws.clear();
		String taxLaw=getInternalStr("PROPERTYTAX");
		if(taxLaw.length()>0)
			taxLaws.put("PROPERTYTAX",taxLaw);
		taxLaw=getInternalStr("TAXEVASION");
		if(taxLaw.length()>0)
			taxLaws.put("TAXEVASION",getInternalBits(taxLaw));
		taxLaw=getInternalStr("TREASURY");
		if(taxLaw.length()>0)
			taxLaws.put("TREASURY",taxLaw);
		taxLaw=getInternalStr("SALESTAX");
		if(taxLaw.length()>0)
			taxLaws.put("SALESTAX",taxLaw);
		taxLaw=getInternalStr("CITTAX");
		if(taxLaw.length()>0)
			taxLaws.put("CITTAX",taxLaw);

		basicCrimes.clear();
		String basicLaw=getInternalStr("MURDER");
		if(basicLaw.length()>0)
			basicCrimes.put("MURDER",getInternalBits(basicLaw));
		basicLaw=getInternalStr("RESISTINGARREST");
		if(basicLaw.length()>0)
			basicCrimes.put("RESISTINGARREST",getInternalBits(basicLaw));
		basicLaw=getInternalStr("NUDITY");
		if(basicLaw.length()>0)
			basicCrimes.put("NUDITY",getInternalBits(basicLaw));
		basicLaw=getInternalStr("ASSAULT");
		if(basicLaw.length()>0)
			basicCrimes.put("ASSAULT",getInternalBits(basicLaw));
		basicLaw=getInternalStr("ARMED");
		if(basicLaw.length()>0)
			basicCrimes.put("ARMED",getInternalBits(basicLaw));
		basicLaw=getInternalStr("TRESPASSING");
		if(basicLaw.length()>0)
			basicCrimes.put("TRESPASSING",getInternalBits(basicLaw));
		basicLaw=getInternalStr("PROPERTYROB");
		if(basicLaw.length()>0)
			basicCrimes.put("PROPERTYROB",getInternalBits(basicLaw));

		abilityCrimes.clear();
		otherCrimes.clear();
		otherBits.clear();
		bannedSubstances.clear();
		bannedBits.clear();
		for(final Enumeration<Object> e=laws.keys();e.hasMoreElements();)
		{
			final String key=(String)e.nextElement();
			final String words=(String)laws.get(key);
			final int x=words.indexOf(';');
			if(x>=0)
			{
				if(key.startsWith("CRIME"))
				{
					otherCrimes.add(CMParms.parse(words.substring(0,x)));
					final String[] bits=new String[Law.BIT_NUMBITS];
					final List<String> parsed=CMParms.parseSemicolons(words.substring(x+1),false);
					for(int i=0;i<Law.BIT_NUMBITS;i++)
					{
						if(i<parsed.size())
						{
							bits[i]=parsed.get(i);
						}
						else
						{
							bits[i]="";
						}
					}
					otherBits.add(bits);
				}
				else
				if(key.startsWith("BANNED"))
				{
					bannedSubstances.add(CMParms.parse(words.substring(0,x)));
					final String[] bits=new String[Law.BIT_NUMBITS];
					final List<String> parsed=CMParms.parseSemicolons(words.substring(x+1),false);
					for(int i=0;i<Law.BIT_NUMBITS;i++)
					{
						if(i<parsed.size())
						{
							bits[i]=parsed.get(i);
						}
						else
						{
							bits[i]="";
						}
					}
					bannedBits.add(bits);
				}
				else
				if((key.startsWith("$")&&(CMClass.getAbility(key.substring(1))!=null))
				||(CMClass.getAbility(key)!=null)
				||(CMParms.containsIgnoreCase(Ability.ACODE_DESCS_,key))
				||(key.startsWith("$")&&CMParms.containsIgnoreCase(Ability.ACODE_DESCS_,key.substring(1)))
				||(CMParms.containsIgnoreCase(Ability.DOMAIN_DESCS,key))
				||(key.startsWith("$")&&CMParms.containsIgnoreCase(Ability.DOMAIN_DESCS,key.substring(1))))
				{
					abilityCrimes.put(key.toUpperCase(),getInternalBits(words));
				}
			}
		}
	}

	@Override
	public String rawLawString()
	{
		if(theLaws!=null)
		{
			final ByteArrayOutputStream out=new ByteArrayOutputStream();
			try{ theLaws.store(out,"");}catch(final IOException e){}
			String s=CMStrings.replaceAll(out.toString(),"\n\r","~");
			s=CMStrings.replaceAll(s,"\r\n","~");
			s=CMStrings.replaceAll(s,"\n","~");
			s=CMStrings.replaceAll(s,"\r","~");
			s=CMStrings.replaceAll(s,"'","`");
			return s;
		}
		return "";
	}

	private String[] getInternalBits(String bitStr)
	{
		final String[] bits=new String[Law.BIT_NUMBITS];
		final List<String> parsed=CMParms.parseSemicolons(bitStr,false);
		for(int i=0;i<Law.BIT_NUMBITS;i++)
		{
			if(i<parsed.size())
				bits[i]=parsed.get(i);
			else
				bits[i]="";
		}
		return bits;
	}

	public LegalWarrant getWarrant(MOB criminal,
								   String crime,
								   boolean pull,
								   boolean debugging)
	{
		LegalWarrant W=null;
		for(int i=0;i<warrants.size();i++)
		{
			final LegalWarrant W2=warrants.elementAt(i);
			if((W2.criminal()==criminal)
			&&(W2.crime().equals(crime))
			&&(legalDetails.isStillACrime(W2,debugging)))
			{
				W=W2;
				if(pull)
					warrants.removeElement(W2);
				break;
			}
		}
		return W;
	}

	@Override
	public LegalWarrant getCopkiller(Area A, LegalBehavior behav, MOB mob)
	{
		final String[] copKillerInfo=basicCrimes().get("MURDER");
		if(copKillerInfo!=null)
		{
			for(int i=0;i<warrants.size();i++)
			{
				final LegalWarrant W=warrants.elementAt(i);
				if((W.criminal()==mob)
				&&(W.crime().equals(copKillerInfo[Law.BIT_CRIMENAME]))
				&&(W.victim()!=null)
				&&(behav!=null)
				&&(behav.isStillACrime(W,false))
				&&(behav.isAnyOfficer(A,W.victim())))
					return W;
			}
		}
		return null;
	}

	@Override
	public LegalWarrant getLawResister(Area A, LegalBehavior behav, MOB mob)
	{
		final String[] lawResistInfo=basicCrimes().get("RESISTINGARREST");
		if(lawResistInfo!=null)
		for(int i=0;i<warrants.size();i++)
		{
			final LegalWarrant W=warrants.elementAt(i);
			if((W.criminal()==mob)
			&&(W.crime().equals(lawResistInfo[Law.BIT_CRIMENAME]))
			&&(W.victim()!=null)
			&&(behav.isStillACrime(W,false))
			&&(behav.isAnyOfficer(A,W.victim())))
				return W;
		}
		return null;
	}


	@Override
	public LegalWarrant getWarrant(MOB mob, int which)
	{
		int one=0;
		for(int i=0;i<warrants.size();i++)
		{
			final LegalWarrant W=warrants.elementAt(i);
			if(W.criminal()==mob)
			{
				if(which==one)
					return W;
				one++;
			}
		}
		return null;
	}

	@Override
	public LegalWarrant getOldWarrant(MOB criminal, String crime, boolean pull)
	{
		LegalWarrant W=null;
		for(int i=0;i<oldWarrants.size();i++)
		{
			final LegalWarrant W2=oldWarrants.elementAt(i);
			if((W2.criminal()==criminal)&&(W2.crime().equals(crime)))
			{
				W=W2;
				if(pull)
					oldWarrants.removeElement(W2);
				break;
			}
		}
		return W;
	}

}