package com.planet_ink.coffee_mud.Abilities.Thief;
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.StdBehavior;
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.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.util.*;

/*
   Copyright 2016-2020 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 Thief_Articles extends ThiefSkill
{
	@Override
	public String ID()
	{
		return "Thief_Articles";
	}

	private final static String	localizedName	= CMLib.lang().L("Articles");

	@Override
	public String name()
	{
		return localizedName;
	}

	private static final String[]	triggerStrings	= I(new String[] { "ARTICLES"});

	@Override
	public String[] triggerStrings()
	{
		return triggerStrings;
	}

	@Override
	public int classificationCode()
	{
		return Ability.ACODE_THIEF_SKILL | Ability.DOMAIN_INFLUENTIAL;
	}

	@Override
	public int abstractQuality()
	{
		return Ability.QUALITY_OK_OTHERS;
	}

	@Override
	public String displayText()
	{
		return "";
	}

	@Override
	protected int canAffectCode()
	{
		return 0;
	}

	@Override
	protected int canTargetCode()
	{
		return Ability.CAN_MOBS;
	}

	@Override
	public int usageType()
	{
		return USAGE_MANA;
	}

	protected int abilityCode = 0;

	@Override
	public int abilityCode()
	{
		return abilityCode;
	}

	@Override
	public void setAbilityCode(final int newCode)
	{
		this.abilityCode = newCode;
	}

	@Override
	public CMObject copyOf()
	{
		final Thief_Articles A=(Thief_Articles)super.copyOf();
		A.sailor=null;
		return A;
	}

	private enum CrewType
	{
		GUNNER,
		DEFENDER,
		BOARDER
	}

	protected String	shipName	= "";
	protected CrewType	type		= CrewType.GUNNER;
	protected Behavior	sailor		= null;

	@Override
	public void setMiscText(final String newMiscText)
	{
		super.setMiscText(newMiscText);
		final int x=newMiscText.indexOf(';');
		if(x>0)
		{
			shipName=newMiscText.substring(0,x);
			type=(CrewType)CMath.s_valueOf(CrewType.class, newMiscText.substring(x+1));
		}
	}

	@Override
	public void affectPhyStats(final Physical affected, final PhyStats affectableStats)
	{
		super.affectPhyStats(affected, affectableStats);
		switch(type)
		{
		case GUNNER:
			affectableStats.addAmbiance(L("Siege Op"));
			break;
		case DEFENDER:
			affectableStats.addAmbiance(L("Defender"));
			break;
		case BOARDER:
			affectableStats.addAmbiance(L("Boarder"));
			break;
		}
	}

	public Behavior getSailor()
	{
		if(affected instanceof PhysicalAgent)
		{
			final PhysicalAgent agent=(PhysicalAgent)affected;
			if((sailor == null)||(agent.fetchBehavior("Sailor")!=sailor))
			{
				final Behavior B=agent.fetchBehavior("Sailor");
				if(B!=null)
					agent.delBehavior(B);
				sailor = CMClass.getBehavior("Sailor");
				switch(type)
				{
				case GUNNER:
					sailor.setParms("FIGHTTECH=true FIGHTMOVER=false TICKBONUS="+abilityCode());
					break;
				case DEFENDER:
					sailor.setParms("DEFENDER=true FIGHTMOVER=false FIGHTTECH=false TICKBONUS="+abilityCode());
					break;
				case BOARDER:
					sailor.setParms("BOARDER=true FIGHTMOVER=false FIGHTTECH=false TICKBONUS="+abilityCode());
					break;
				}
				sailor.setSavable(false);
				((PhysicalAgent)affected).addBehavior(sailor);
			}
		}
		return sailor;
	}

	@Override
	public void unInvoke()
	{
		final Physical affected=this.affected;
		if(affected instanceof PhysicalAgent)
		{
			final PhysicalAgent agent=(PhysicalAgent)affected;
			final Behavior B=agent.fetchBehavior("Sailor");
			if(B!=null)
				agent.delBehavior(B);
		}
		super.unInvoke();
	}

	@Override
	public boolean okMessage(final Environmental host, final CMMsg msg)
	{
		if(!super.okMessage(host, msg))
			return false;
		return true;
	}

	@Override
	public void executeMsg(final Environmental affecting, final CMMsg msg)
	{
		super.executeMsg(affecting, msg);
	}

	@Override
	public boolean tick(final Tickable ticking, final int tickID)
	{
		if(!super.tick(ticking,tickID))
			return false;
		getSailor();
		return true;
	}

	protected boolean isCrew(final MOB M, final String shipName)
	{
		final Thief_Articles articlesA=(Thief_Articles)M.fetchEffect(ID());
		return ((articlesA!=null)&&(articlesA.shipName.equals(shipName)));
	}

	protected String getCrewShip(final MOB M)
	{
		final Thief_Articles articlesA=(Thief_Articles)M.fetchEffect(ID());
		return (articlesA!=null) ? articlesA.shipName : "";
	}

	protected CrewType getCrewType(final MOB M)
	{
		final Thief_Articles articlesA=(Thief_Articles)M.fetchEffect(ID());
		return (articlesA!=null) ? articlesA.type : null;
	}

	@Override
	public boolean invoke(final MOB mob, final List<String> commands, final Physical givenTarget, final boolean auto, final int asLevel)
	{
		final Room R=mob.location();
		if(R==null)
			return false;
		if(!(R.getArea() instanceof BoardableShip))
		{
			mob.tell(L("You must be on a sailing ship."));
			return false;
		}
		final BoardableShip myShip=(BoardableShip)R.getArea();
		final Item myShipItem=myShip.getShipItem();
		final Area myShipArea=myShip.getShipArea();
		if((myShipItem==null)
		||(myShipArea==null)
		||(!(myShipItem.owner() instanceof Room)))
		{
			mob.tell(L("You must be on your sailing ship."));
			return false;
		}

		if((!CMLib.law().doesHavePriviledgesHere(mob, R))
		&&(!CMSecurity.isAllowed(mob, R, CMSecurity.SecFlag.CMDMOBS)))
		{
			mob.tell(L("You must be on the deck of a ship that you have privileges on."));
			return false;
		}

		final MOB target=this.getTarget(mob,commands,givenTarget);
		if(target==null)
			return false;

		if((!target.isMonster())
		||(CMLib.flags().isAnimalIntelligence(target))
		||((target.getStartRoom()==null)&&(target.fetchEffect(ID())==null)))
		{
			mob.tell(L("You can't offer the articles to @x1.",target.name(mob)));
			return false;
		}

		if(isCrew(target,myShipItem.Name()))
		{
			mob.tell(L("@x1 has already signed the articles.",target.name(mob)));
			return false;
		}

		boolean allowedToOfferToThem=false;
		if(CMLib.flags().isBoundOrHeld(target))
		{
			allowedToOfferToThem=true;
		}

		if(mob.getGroupMembers(new HashSet<MOB>()).contains(target))
		{
			allowedToOfferToThem=true;
		}

		if(!allowedToOfferToThem)
		{
			mob.tell(L("You can't offer @x1 the articles.",target.name()));
			return false;
		}

		int numRooms=0;
		int numCrew=0;
		int numDecks=0;
		final int[] numTypes=new int[CrewType.values().length];
		for(final Enumeration<Room> r=myShipArea.getProperMap();r.hasMoreElements();)
		{
			final Room R2=r.nextElement();
			switch(R2.domainType())
			{
			case Room.DOMAIN_INDOORS_AIR:
			case Room.DOMAIN_OUTDOORS_AIR:
				break;
			default:
				if(((R2.domainType()&Room.INDOORS)!=0))
					numDecks++;
				numRooms++;
				break;
			}
			for(final Enumeration<MOB> m=R2.inhabitants();m.hasMoreElements();)
			{
				final MOB M=m.nextElement();
				if((M!=null)
				&&(M.isMonster())
				&&(isCrew(M,myShipItem.Name())))
				{
					numCrew++;
					numTypes[getCrewType(M).ordinal()]++;
				}
			}
		}

		final int bonus= ( adjustedLevel(mob,asLevel) / 10);
		if(bonus > 0)
		{
			final int bonusDecks = bonus / 2;
			numRooms += bonus;
			numDecks += bonusDecks;
		}

		CrewType nextType = null;
		final int maxGunners = numDecks;
		int maxBoarders = (numRooms-numDecks)/2;
		if(maxBoarders<1)
			maxBoarders=1;
		int maxDefenders = (numRooms-numDecks - maxBoarders);
		if(maxDefenders<1)
			maxDefenders=1;

		if(numCrew >= (maxGunners + maxBoarders + maxDefenders))
		{
			mob.tell(L("This ship already has the maximum crew."));
			return false;
		}

		int attempts=10000;
		while((nextType == null)&&(--attempts>0))
		{
			nextType = CrewType.values()[CMLib.dice().roll(1, CrewType.values().length, -1)];
			if(numTypes[nextType.ordinal()]>0)
			{
				switch(nextType)
				{
				case GUNNER:
					if(numTypes[nextType.ordinal()]>=numDecks)
						nextType=null;
					break;
				case DEFENDER:
					if(numTypes[nextType.ordinal()]>=maxDefenders)
						nextType=null;
					break;
				case BOARDER:
					if(numTypes[nextType.ordinal()]>=maxBoarders)
						nextType=null;
					break;
				}
			}
		}

		if(nextType == null)
		{
			mob.tell(L("This ship already has enough crew."));
			return false;
		}

		if(!super.invoke(mob,commands,givenTarget,auto,asLevel))
			return false;

		final int adjustment=target.phyStats().level()-((mob.phyStats().level()+super.getXLEVELLevel(mob))/2);
		final boolean success=proficiencyCheck(mob,-adjustment,auto);
		if(success)
		{
			final String str=auto?"":L("^S<S-NAME> offer(s) <T-NAME> the articles of piracy..^?");
			final CMMsg msg=CMClass.getMsg(mob,target,this,CMMsg.MSG_THIEF_ACT,str,CMMsg.MSG_THIEF_ACT|(auto?CMMsg.MASK_ALWAYS:0),str,CMMsg.MSG_NOISYMOVEMENT,str);
			if(R.okMessage(mob,msg))
			{
				R.send(mob,msg);
				if(msg.value()<=0)
				{
					R.show(target, null, CMMsg.MSG_QUIETMOVEMENT,L("<S-NAME> sign(s) the articles of piracy and is now a member of the crew of @x1.",myShipItem.name()));
					Ability A=target.fetchEffect(ID());
					if(A!=null)
						target.delEffect(A);
					A=(Ability)copyOf();
					A.setMiscText(myShipItem.Name()+";"+nextType.name());
					A.setAbilityCode(super.getXLEVELLevel(mob));
					target.addNonUninvokableEffect(A);
				}
			}
		}
		else
			return beneficialWordsFizzle(mob,target,L("<S-NAME> offer(s) <T-NAME> the pirate articles, but <T-HIM-HER> isn't convinced."));

		// return whether it worked
		return success;
	}
}
