package com.planet_ink.coffee_mud.Libraries;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.*;
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.io.IOException;
import java.util.*;
import java.util.regex.*;

/* 
   Copyright 2000-2006 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 RawCMaterial extends StdLibrary implements MaterialLibrary
{
    public String ID(){return "RawCMaterial";}
 
	public int getRandomResourceOfMaterial(int material)
	{
		material=material&RawMaterial.MATERIAL_MASK;
		if((material<0)||(material>=RawMaterial.MATERIAL_DESCS.length))
			return -1;
		int d=CMLib.dice().roll(1,RawMaterial.RESOURCE_DATA.length,0);
		while(d>0)
		for(int i=0;i<RawMaterial.RESOURCE_DATA.length;i++)
			if((RawMaterial.RESOURCE_DATA[i][0]&RawMaterial.MATERIAL_MASK)==material)
				if((--d)==0)
					return RawMaterial.RESOURCE_DATA[i][0];
		return -1;
	}

	public boolean quickDestroy(Item I)
	{
		if(I==null) return false;
		if(I.owner() instanceof MOB)
			((MOB)I.owner()).delInventory(I);
		else
		if(I.owner() instanceof Room)
			((Room)I.owner()).delItem(I);
		I.setOwner(null);
		I.destroy();
		return true;
	}
	
	public boolean rebundle(Item item)
	{
		if((item==null)||(item.amDestroyed())) 
            return false;
		Vector found=new Vector();
		found.addElement(item);
		Item I=null;
		Environmental owner=item.owner();
	    long lowestNonZeroFoodNumber=Long.MAX_VALUE;
		if(owner instanceof Room)
		{
			Room R=(Room)item.owner();
		    for(int i=0;i<R.numItems();i++)
		    {
		        I=R.fetchItem(i);
				if((I instanceof RawMaterial)
				&&(I.material()==item.material())
			    &&(I!=item)
				&&(!CMLib.flags().isOnFire(I))
				&&(!CMLib.flags().enchanted(I))
				&&(I.container()==item.container()))
				{
					found.addElement(I);
				}
		    }
		}
		else
		if(owner instanceof MOB)
		{
			MOB M=(MOB)item.owner();
		    for(int i=0;i<M.inventorySize();i++)
		    {
		        I=M.fetchInventory(i);
				if((I instanceof RawMaterial)
				&&(I.material()==item.material())
			    &&(I!=item)
				&&(!CMLib.flags().isOnFire(I))
				&&(!CMLib.flags().enchanted(I))
				&&(I.container()==item.container()))
				{
					found.addElement(I);
				}
		    }
		}
		else
			return false;
		if(found.size()<2) return false;
		Item bundle=null;
		int maxFound=1;
		int totalWeight=0;
		int totalValue=0;
		int totalNourishment=0;
		int totalThirstHeld=0;
		int totalThirstRemain=0;
		for(int i=0;i<found.size();i++)
		{
			I=(Item)found.elementAt(i);
			int weight=I.baseEnvStats().weight();
			totalWeight+=weight;
			totalValue+=I.baseGoldValue();
			if(weight>maxFound)
			{
				maxFound=weight;
				bundle=(Item)found.elementAt(i);
			}
		    if((I instanceof Food)
		    &&(((Food)I).decayTime()>0)
		    &&(((Food)I).decayTime()<lowestNonZeroFoodNumber))
		        lowestNonZeroFoodNumber=((Food)I).decayTime();
		    if(I instanceof Food)
		    	totalNourishment+=((Food)I).nourishment();
		    if(I instanceof Drink)
		    {
		    	totalThirstHeld+=((Drink)I).liquidHeld();
		    	totalThirstRemain+=((Drink)I).liquidRemaining();
		    }
		}
		if(bundle==null) bundle=item;
		found.removeElement(bundle);
	    if(lowestNonZeroFoodNumber==Long.MAX_VALUE) lowestNonZeroFoodNumber=0;
	    Hashtable foundAblesH=new Hashtable();
	    Ability A=null;
		for(int i=0;i<found.size();i++)
		{
			I=(Item)found.elementAt(i);
		    for(int a=0;a<I.numEffects();a++)
		    {
		        A=I.fetchEffect(a);
		        if((A!=null)
		        &&(!A.canBeUninvoked())
		        &&(!foundAblesH.containsKey(A.ID())))
		            foundAblesH.put(A.ID(),A);
		    }
		}
		bundle.setName("a "+totalWeight+"# "+RawMaterial.RESOURCE_DESCS[bundle.material()&RawMaterial.RESOURCE_MASK].toLowerCase()+" bundle");
		bundle.setDisplayText(bundle.name()+" is here.");
		bundle.baseEnvStats().setWeight(totalWeight);
		bundle.setBaseValue(totalValue);
		if(bundle instanceof Food)
		    ((Food)bundle).setNourishment(totalNourishment);
		if(bundle instanceof Drink)
		{
		    ((Drink)bundle).setLiquidHeld(totalThirstHeld);
		    ((Drink)bundle).setLiquidRemaining(totalThirstRemain);
		}
		if(bundle instanceof Food)
		    ((Food)bundle).setDecayTime(lowestNonZeroFoodNumber);
		for(Enumeration e=foundAblesH.keys();e.hasMoreElements();)
		{
			A=(Ability)foundAblesH.get(e.nextElement());
			if(bundle.fetchEffect(A.ID())==null)
				bundle.addNonUninvokableEffect((Ability)A.copyOf());
		}
		for(int i=0;i<found.size();i++)
			((RawMaterial)found.elementAt(i)).quickDestroy();
        if((owner instanceof Room)&&(((Room)owner).numItems()>0)&&(((Room)owner).fetchItem(((Room)owner).numItems()-1)!=bundle))
        {
            ((Room)owner).delItem(bundle);
            ((Room)owner).bringItemHere(bundle,Item.REFUSE_PLAYER_DROP,false);
        }
        if((owner instanceof MOB)&&(((MOB)owner).inventorySize()>0)&&(((MOB)owner).fetchInventory(((MOB)owner).inventorySize()-1)!=bundle))
        {
            ((MOB)owner).delInventory(bundle);
            ((MOB)owner).giveItem(bundle);
        }
		Room R=CMLib.map().roomLocation(bundle);
		if(R!=null) R.recoverRoomStats();
		return true;
	}
	
    public Environmental unbundle(Item I, int number)
    {
        if((I==null)||(I.amDestroyed())) 
            return null;
        if((I instanceof PackagedItems)
        &&(I.container()==null)
        &&(!CMLib.flags().isOnFire(I)))
        {
            if(number<=0) number=((PackagedItems)I).numberOfItemsInPackage();
            if(number<=0) number=1;
            if(number>((PackagedItems)I).numberOfItemsInPackage())
                number=((PackagedItems)I).numberOfItemsInPackage();
            Environmental owner=I.owner();
            Vector parts=((PackagedItems)I).unPackage(number);
            if(parts.size()==0) return I;
            for(int p=0;p<parts.size();p++)
            {
                I=(Item)parts.elementAt(p);
                if(owner instanceof Room)
                    ((Room)owner).addItemRefuse(I,Item.REFUSE_PLAYER_DROP);
                else
                if(owner instanceof MOB)
                    ((MOB)owner).addInventory(I);
            }
            return I;
        }
        else
        if((I instanceof RawMaterial)
        &&(I.container()==null)
        &&(!CMLib.flags().isOnFire(I))
        &&(!CMLib.flags().enchanted(I)))
        {
            Ability rott=I.fetchEffect("Poison_Rotten");
            if(I.baseEnvStats().weight()>1)
            {
                Environmental owner=I.owner();
                if(number<=0) number=I.baseEnvStats().weight();
                if(number<=0) number=1;
                if(number>=(I.baseEnvStats().weight()-1))
                    number=I.baseEnvStats().weight();
                I.baseEnvStats().setWeight(I.baseEnvStats().weight());
                int loseValue=0;
                int loseNourishment=0;
                int loseThirstHeld=0;
                int loseThirstRemain=0;
                Environmental E=null;
                for(int x=0;x<number;x++)
                {
                    E=makeResource(I.material(),-1,true);
                    if(E instanceof Item)
                    {
                        loseValue+=I.baseGoldValue();
                        if((E instanceof Food)&&(I instanceof Food))
                        {
                            ((Food)E).setDecayTime(((Food)I).decayTime());
                            loseNourishment+=((Food)E).nourishment();
                        }
                        if((E instanceof Drink)&&(I instanceof Drink))
                        {
                            loseThirstHeld+=((Drink)E).liquidHeld();
                            loseThirstRemain+=((Drink)E).liquidRemaining();
                        }
                        if(rott!=null)
                            E.addNonUninvokableEffect((Ability)rott.copyOf());
                        if(owner instanceof Room)
                            ((Room)owner).addItemRefuse((Item)E,Item.REFUSE_PLAYER_DROP);
                        else
                        if(owner instanceof MOB)
                            ((MOB)owner).addInventory((Item)E);
                    }
                    else
                        E=null;
                }
                if((I.baseEnvStats().weight()-number)>1)
                {
                    I.baseEnvStats().setWeight(I.baseEnvStats().weight()-number);
                    I.setBaseValue(I.baseGoldValue()-loseValue);
                    I.setName("a "+I.baseEnvStats().weight()+"# "+RawMaterial.RESOURCE_DESCS[I.material()&RawMaterial.RESOURCE_MASK].toLowerCase()+" bundle");
                    I.setDisplayText(I.name()+" is here.");
                    if(I instanceof Food)
                    {
                        ((Food)I).setNourishment(((Food)I).nourishment()-loseNourishment);
                        if(((Food)I).nourishment()<=0)
                            ((Food)I).setNourishment(0);
                    }
                    if(I instanceof Drink)
                    {
                        ((Drink)I).setLiquidHeld(((Drink)I).liquidHeld()-loseThirstHeld);
                        if(((Drink)I).liquidHeld()<=0)
                            ((Drink)I).setLiquidHeld(0);
                        ((Drink)I).setLiquidRemaining(((Drink)I).liquidRemaining()-loseThirstRemain);
                        if(((Drink)I).liquidRemaining()<=0)
                            ((Drink)I).setLiquidRemaining(0);
                    }
                    I.recoverEnvStats();
                    // now move it to the end!
                    if(owner instanceof Room)
                    {
                        ((Room)owner).delItem(I);
                        ((Room)owner).addItemRefuse(I,Item.REFUSE_PLAYER_DROP);
                    }
                    else
                    if(owner instanceof MOB)
                    {
                        ((MOB)owner).delInventory(I);
                        ((MOB)owner).addInventory(I);
                    }
                    else
                        I.destroy();
                }
                else
                    I.destroy();
                return E;
            }
            return I;
        }
        return null;
    }
    
	public int getMaterialRelativeInt(String s)
	{
		for(int i=0;i<RawMaterial.MATERIAL_DESCS.length;i++)
			if(s.equalsIgnoreCase(RawMaterial.MATERIAL_DESCS[i]))
				return i;
		return -1;
	}
    public int getMaterialCode(String s, boolean exact)
    {
        for(int i=0;i<RawMaterial.MATERIAL_DESCS.length;i++)
            if(s.equalsIgnoreCase(RawMaterial.MATERIAL_DESCS[i]))
                return i<<8;
    	if(exact) return -1;
		s=s.toUpperCase();
		for(int i=0;i<RawMaterial.MATERIAL_DESCS.length;i++)
			if(RawMaterial.MATERIAL_DESCS[i].startsWith(s)||s.startsWith(RawMaterial.MATERIAL_DESCS[i]))
				return i<<8;
        return -1;
    }
    public int getResourceCode(String s, boolean exact)
	{
		for(int i=0;i<RawMaterial.RESOURCE_DESCS.length;i++)
		{
			if(s.equalsIgnoreCase(RawMaterial.RESOURCE_DESCS[i]))
				return RawMaterial.RESOURCE_DATA[i][0];
		}
    	if(exact) return -1;
		s=s.toUpperCase();
		for(int i=0;i<RawMaterial.RESOURCE_DESCS.length;i++)
			if(RawMaterial.RESOURCE_DESCS[i].startsWith(s)||s.startsWith(RawMaterial.RESOURCE_DESCS[i]))
				return RawMaterial.RESOURCE_DATA[i][0];
		return -1;
	}
	
	public Environmental makeResource(int myResource, int localeCode, boolean noAnimals)
	{
		if(myResource<0)
			return null;
		int material=(myResource&RawMaterial.MATERIAL_MASK);
        
		Item I=null;
		String name=RawMaterial.RESOURCE_DESCS[myResource&RawMaterial.RESOURCE_MASK].toLowerCase();
		if(!noAnimals)
		{
			if((myResource==RawMaterial.RESOURCE_WOOL)
			||(myResource==RawMaterial.RESOURCE_FEATHERS)
			||(myResource==RawMaterial.RESOURCE_SCALES)
			||(myResource==RawMaterial.RESOURCE_HIDE)
			||(myResource==RawMaterial.RESOURCE_FUR))
			   material=RawMaterial.MATERIAL_LEATHER;
			for(int i=0;i<RawMaterial.FISHES.length;i++)
				if(RawMaterial.FISHES[i]==myResource)
				{ material=RawMaterial.MATERIAL_VEGETATION; break;}
			if((material==RawMaterial.MATERIAL_LEATHER)
			||(material==RawMaterial.MATERIAL_FLESH))
			{
				switch(myResource)
				{
				case RawMaterial.RESOURCE_MUTTON:
				case RawMaterial.RESOURCE_WOOL:
					return CMClass.getMOB("Sheep");
				case RawMaterial.RESOURCE_LEATHER:
				case RawMaterial.RESOURCE_HIDE:
					switch(CMLib.dice().roll(1,10,0))
					{
					case 1:
					case 2:
					case 3: return CMClass.getMOB("Cow");
					case 4: return CMClass.getMOB("Bull");
					case 5:
					case 6:
					case 7: return CMClass.getMOB("Doe");
					case 8:
					case 9:
					case 10: return CMClass.getMOB("Buck");
					}
					break;
				case RawMaterial.RESOURCE_PORK:
					return CMClass.getMOB("Pig");
				case RawMaterial.RESOURCE_FUR:
				case RawMaterial.RESOURCE_MEAT:
					switch(CMLib.dice().roll(1,10,0))
					{
					case 1:
					case 2:
					case 3:
					case 4: return CMClass.getMOB("Wolf");
					case 5:
					case 6:
					case 7: return CMClass.getMOB("Buffalo");
					case 8:
					case 9: return CMClass.getMOB("BrownBear");
					case 10: return CMClass.getMOB("BlackBear");
					}
					break;
				case RawMaterial.RESOURCE_SCALES:
					switch(CMLib.dice().roll(1,10,0))
					{
					case 1:
					case 2:
					case 3:
					case 4: return CMClass.getMOB("Lizard");
					case 5:
					case 6:
					case 7: return CMClass.getMOB("GardenSnake");
					case 8:
					case 9: return CMClass.getMOB("Cobra");
					case 10: return CMClass.getMOB("Python");
					}
					break;
				case RawMaterial.RESOURCE_POULTRY:
				case RawMaterial.RESOURCE_EGGS:
					return CMClass.getMOB("Chicken");
				case RawMaterial.RESOURCE_BEEF:
					switch(CMLib.dice().roll(1,5,0))
					{
					case 1:
					case 2:
					case 3:
					case 4: return CMClass.getMOB("Cow");
					case 5: return CMClass.getMOB("Bull");
					}
					break;
				case RawMaterial.RESOURCE_FEATHERS:
					switch(CMLib.dice().roll(1,4,0))
					{
					case 1: return CMClass.getMOB("WildEagle");
					case 2: return CMClass.getMOB("Falcon");
					case 3: return CMClass.getMOB("Chicken");
					case 4: return CMClass.getMOB("Parakeet");
					}
					break;
				}
			}
        }
		switch(material)
		{
		case RawMaterial.MATERIAL_FLESH:
			I=CMClass.getItem("GenFoodResource");
			break;
		case RawMaterial.MATERIAL_VEGETATION:
		{
			if(myResource==RawMaterial.RESOURCE_VINE)
				I=CMClass.getItem("GenResource");
			else
			{
				I=CMClass.getItem("GenFoodResource");
				if(myResource==RawMaterial.RESOURCE_HERBS)
					((Food)I).setNourishment(1);
			}
			break;
		}
		case RawMaterial.MATERIAL_LIQUID:
		case RawMaterial.MATERIAL_ENERGY:
		{
			I=CMClass.getItem("GenLiquidResource");
			break;
		}
		case RawMaterial.MATERIAL_LEATHER:
		case RawMaterial.MATERIAL_CLOTH:
		case RawMaterial.MATERIAL_PAPER:
		case RawMaterial.MATERIAL_WOODEN:
		case RawMaterial.MATERIAL_GLASS:
		case RawMaterial.MATERIAL_PLASTIC:
		case RawMaterial.MATERIAL_ROCK:
		case RawMaterial.MATERIAL_PRECIOUS:
		{
			I=CMClass.getItem("GenResource");
			break;
		}
		case RawMaterial.MATERIAL_METAL:
		case RawMaterial.MATERIAL_MITHRIL:
		{
			I=CMClass.getItem("GenResource");
			if((myResource!=RawMaterial.RESOURCE_ADAMANTITE)
			&&(myResource!=RawMaterial.RESOURCE_BRASS)
			&&(myResource!=RawMaterial.RESOURCE_BRONZE)
			&&(myResource!=RawMaterial.RESOURCE_STEEL))
				name=name+" ore";
			break;
		}
		}
		if(I!=null)
		{
			I.setMaterial(myResource);
			if(I instanceof Drink)
				((Drink)I).setLiquidType(myResource);
			I.setBaseValue(RawMaterial.RESOURCE_DATA[myResource&RawMaterial.RESOURCE_MASK][1]);
			I.baseEnvStats().setWeight(1);
			if(I instanceof RawMaterial)
				((RawMaterial)I).setDomainSource(localeCode);
			if(I instanceof Drink)
				I.setName("some "+name);
			else
				I.setName("a pound of "+name);
			I.setDisplayText("some "+name+" sits here.");
			I.setDescription("");
			I.recoverEnvStats();
			return I;
		}
		return null;
	}
	
	public Item makeItemResource(int type)
	{
		Item I=null;
		String name=RawMaterial.RESOURCE_DESCS[type&RawMaterial.RESOURCE_MASK].toLowerCase();
		if(((type&RawMaterial.MATERIAL_MASK)==RawMaterial.MATERIAL_FLESH)
		||((type&RawMaterial.MATERIAL_MASK)==RawMaterial.MATERIAL_VEGETATION))
			I=CMClass.getItem("GenFoodResource");
		else
		if((type&RawMaterial.MATERIAL_MASK)==RawMaterial.MATERIAL_LIQUID)
			I=CMClass.getItem("GenLiquidResource");
		else
			I=CMClass.getItem("GenResource");
		if(I instanceof Drink)
			I.setName("some "+name);
		else
			I.setName("a pound of "+name);
		I.setDisplayText("some "+name+" sits here.");
		I.setDescription("");
		I.setMaterial(type);
		I.setBaseValue(RawMaterial.RESOURCE_DATA[type&RawMaterial.RESOURCE_MASK][1]);
		I.baseEnvStats().setWeight(1);
		I.recoverEnvStats();
		return I;
	}
    
    
    public int destroyResources(Room room,
                                int howMuch,
                                int finalMaterial,
                                int otherMaterial,
                                Item never)
    {
        int lostValue=0;
        if(room==null) return 0;
        
        Environmental lastE1=null;
        Environmental lastE2=null;
        if((howMuch>0)||(otherMaterial>0))
        for(int i=room.numItems()-1;i>=0;i--)
        {
            Item I=room.fetchItem(i);
            if(I==null) break;
            if(I==never) continue;

            if((otherMaterial>0)
            &&(I instanceof RawMaterial)
            &&(I.material()==otherMaterial)
            &&(I.container()==null)
            &&(!CMLib.flags().isOnFire(I))
            &&(!CMLib.flags().enchanted(I)))
            {
                if(I.baseEnvStats().weight()>1)
                {
                    I.baseEnvStats().setWeight(I.baseEnvStats().weight()-1);
                    Environmental E=null;
                    for(int x=0;x<I.baseEnvStats().weight();x++)
                    {
                        E=CMLib.materials().makeResource(otherMaterial,-1,true);
                        if(E instanceof Item)
                            room.addItemRefuse((Item)E,Item.REFUSE_PLAYER_DROP);
                    }
                    if(E instanceof Item)
                        lostValue+=((Item)E).value();
                    if(E!=null) lastE1=E;
                    ((RawMaterial)I).quickDestroy(); 
                }
                else
                {
                    lostValue+=I.value();
                    ((RawMaterial)I).quickDestroy();
                }
                otherMaterial=-1;
                if((finalMaterial<0)||(howMuch<=0)) break;
            }
            else
            if((I instanceof RawMaterial)
            &&(I.material()==finalMaterial)
            &&(I.container()==null)
            &&(!CMLib.flags().isOnFire(I))
            &&(!CMLib.flags().enchanted(I))
            &&(howMuch>0))
            {
                if(I.baseEnvStats().weight()>howMuch)
                {
                    I.baseEnvStats().setWeight(I.baseEnvStats().weight()-howMuch);
                    Environmental E=null;
                    for(int x=0;x<I.baseEnvStats().weight();x++)
                    {
                        E=CMLib.materials().makeResource(finalMaterial,-1,true);
                        if(E instanceof Item)
                            room.addItemRefuse((Item)E,Item.REFUSE_PLAYER_DROP);
                    }
                    if(E instanceof Item)
                        lostValue+=(((Item)E).value()*howMuch);
                    if(E!=null) lastE2=E;
                    ((RawMaterial)I).quickDestroy();
                    howMuch=0;
                }
                else
                {
                    howMuch-=I.baseEnvStats().weight();
                    lostValue+=I.value();
                    ((RawMaterial)I).quickDestroy();
                }
                if(howMuch<=0)
                {
                    finalMaterial=-1;
                    if(otherMaterial<0) break;
                }
            }
        }
        if((lastE1 instanceof Item)&&(!((Item)lastE1).amDestroyed()))
            CMLib.materials().rebundle((Item)lastE1);
        if((lastE2 instanceof Item)&&(!((Item)lastE2).amDestroyed()))
            CMLib.materials().rebundle((Item)lastE2);
        return lostValue;
    }
}
