StimPack* DroidStimpackModuleDataComponent::findStimPack() {
	StimPack* pack = NULL;
	float biggest = 0;
	DroidComponent* container = cast<DroidComponent*>(getParent());

	if (container == NULL)
		return NULL;

	ManagedReference<SceneObject*> craftingComponents = container->getSlottedObject("crafted_components");

	if (craftingComponents != NULL) {
		SceneObject* satchel = craftingComponents->getContainerObject(0);

		for (int i = 0; i < satchel->getContainerObjectsSize(); ++i) {
			ManagedReference<SceneObject*> sceno = satchel->getContainerObject(i);

			// is a stimpack
			if (sceno->isPharmaceuticalObject()) {
				PharmaceuticalObject* pharma = sceno.castTo<PharmaceuticalObject*>();

				if (pharma->isStimPack() && !pharma->isPetStimPack() && !pharma->isDroidRepairKit()) {
					StimPack* stim = cast<StimPack*>(pharma);

					if (stim->getEffectiveness() > biggest) {
						biggest = stim->getEffectiveness();
						pack = stim;
					}
				}
			}
		}
	}

	return pack;
}
void DroidMaintenanceModuleDataComponent::copy(BaseDroidModuleComponent* other){

	DroidMaintenanceModuleDataComponent* otherModule = cast<DroidMaintenanceModuleDataComponent*>(other);
	if( otherModule == NULL )
		return;

	moduleRating = otherModule->moduleRating;

	// Save stat in parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL)
		return;

	droidComponent->addProperty("struct_module", moduleRating, 0, "exp_effectiveness");

	if (moduleRating < 6) {
		maxStructures = 3;
	} else if (moduleRating < 12) {
		maxStructures = 6;
	} else if (moduleRating < 15) {
		maxStructures = 9;
	} else {
		maxStructures = 10;
	}
}
void DroidDeedImplementation::processModule(BaseDroidModuleComponent* module, uint32 crc) {
	if (module == NULL)
		return;
	if (module->isStackable()) {
		if (modules.containsKey(module->getModuleName())) {
			// add to the stack if stackable.
			DroidComponent* comp = modules.get(module->getModuleName());
			BaseDroidModuleComponent* bmodule = cast<BaseDroidModuleComponent*>(comp->getDataObjectComponent()->get());
			bmodule->addToStack(module);
		} else {
			ManagedReference<DroidComponent*> dcomp = (this->getZoneServer()->createObject(crc,1)).castTo<DroidComponent*>();
			dcomp->setParent(NULL);
			BaseDroidModuleComponent* bmodule = cast<BaseDroidModuleComponent*>(dcomp->getDataObjectComponent()->get());
			bmodule->copy(module);
			bmodule->setSpecies(species);
			modules.put(module->getModuleName(),dcomp);
		}
	} else {
		ManagedReference<DroidComponent*> dcomp = (this->getZoneServer()->createObject(crc,1)).castTo<DroidComponent*>();
		dcomp->setParent(NULL);
		BaseDroidModuleComponent* bmodule = cast<BaseDroidModuleComponent*>(dcomp->getDataObjectComponent()->get());
		bmodule->copy(module);
		bmodule->setSpecies(species);
		modules.put(module->getModuleName(),dcomp);
	}

}
StimPack* DroidStimpackModuleDataComponent::compatibleStimpack(float power) {
    DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
    if (droidComponent == NULL) {
        info("droidComponent was null");
        return NULL;
    }
    DroidObject* droid = getDroidObject();
    if (droid == NULL) {
        return NULL;
    }
    Locker dlock(droid);
    ManagedReference<SceneObject*> craftingComponents = droidComponent->getSlottedObject("crafted_components");
    if(craftingComponents != NULL) {
        SceneObject* satchel = craftingComponents->getContainerObject(0);
        if(satchel == NULL) {
            return NULL;
        }
        for (int i = 0; i < satchel->getContainerObjectsSize(); ++i) {
            SceneObject* item = satchel->getContainerObject(i);
            if (!item->isTangibleObject())
                continue;

            TangibleObject* tano = cast<TangibleObject*>( item);
            if (tano->isPharmaceuticalObject()) {
                StimPack* stim = cast<StimPack*>(tano);
                if(stim->getEffectiveness() == power) {
                    return stim;
                }
            }
        }
    }
    return NULL;
}
void DroidMaintenanceModuleDataComponent::addToStack(BaseDroidModuleComponent* other){

	DroidMaintenanceModuleDataComponent* otherModule = cast<DroidMaintenanceModuleDataComponent*>(other);
	if( otherModule == NULL )
		return;

	// Maintenance modules do not stack.  Just keep the highest rated module
	if( otherModule->moduleRating > moduleRating )
		moduleRating = otherModule->moduleRating;

	// Save stat in parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL)
		return;

	// Attribute should have already been created in copy method
	if( !droidComponent->changeAttributeValue( "struct_module", moduleRating) ){
		info( "addToStack updateAttributeValue failed");
		return;
	}

	if (moduleRating < 6) {
		maxStructures = 3;
	} else if (moduleRating < 12) {
		maxStructures = 6;
	} else if (moduleRating < 15) {
		maxStructures = 9;
	} else {
		maxStructures = 10;
	}

}
void DroidDetonationModuleDataComponent::setSpecies(int i) {
	species = i;
	mseDroid = i == DroidObject::MSE;

	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent != NULL) {
		droidComponent->addProperty("species", (float)species, 0, "hidden", true);
	}
}
void DroidDetonationModuleDataComponent::initializeTransientMembers() {

	// Pull module stat from parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL) {
		info("droidComponent was null");
		return;
	}

	/*for (int i = 0; i < droidComponent->getPropertyCount(); i++) {
		String prop = droidComponent->getProperty(i);
	}*/

	if (droidComponent->hasKey("bomb_level")) {
		rating = droidComponent->getAttributeValue("bomb_level");
	}

	if (droidComponent->hasKey("module_count")) {
		moduleCount = droidComponent->getAttributeValue("module_count");
	}

	if (droidComponent->hasKey("module_init")) {
		initialized = droidComponent->getAttributeValue("module_init") == 1;
	}

	if (droidComponent->hasKey("species")) {
		species = droidComponent->getAttributeValue("species");
	}

	if (species == DroidObject::MSE) {
		mseDroid = true;
	}
}
void DroidStimpackModuleDataComponent::copy(BaseDroidModuleComponent* other) {
    DroidStimpackModuleDataComponent* otherModule = cast<DroidStimpackModuleDataComponent*>(other);
    if(otherModule == NULL)
        return;
    speed = speed + otherModule->speed;
    capacity = capacity + otherModule->capacity;
    DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
    if (droidComponent != NULL) {
        droidComponent->addProperty("stimpack_speed",(float)speed,0,"exp_effectiveness");
        droidComponent->addProperty("stimpack_capacity",(float)capacity,0,"exp_durability");
    }
}
void DroidStimpackModuleDataComponent::addToStack(BaseDroidModuleComponent* other) {
    DroidStimpackModuleDataComponent* otherModule = cast<DroidStimpackModuleDataComponent*>(other);
    if(otherModule == NULL)
        return;
    speed = speed + otherModule->speed;
    capacity = capacity + otherModule->capacity;
    DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
    if (droidComponent != NULL) {
        droidComponent->changeAttributeValue("stimpack_capacity",(float)capacity);
        droidComponent->changeAttributeValue("stimpack_speed",(float)speed);
    }
}
void DroidMaintenanceModuleDataComponent::initializeTransientMembers() {

	// Pull module stat from parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL) {
		info("droidComponent was null");
		return;
	}

	if( droidComponent->hasKey( "struct_module") ){
		moduleRating = droidComponent->getAttributeValue( "struct_module");
	}
}
void DroidStimpackModuleDataComponent::initializeTransientMembers() {
    DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
    if (droidComponent == NULL) {
        info("droidComponent was null");
        return;
    }
    if(droidComponent->hasKey( "stimpack_capacity")) {
        capacity = droidComponent->getAttributeValue( "stimpack_capacity");
    }
    if (droidComponent->hasKey("stimpack_speed")) {
        speed = droidComponent->getAttributeValue("stimpack_speed");
    }
}
void DroidArmorModuleDataComponent::initializeTransientMembers() {

	// Pull module stat from parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL) {
		info("droidComponent was null");
		return;
	}

	if (droidComponent->hasKey("armor_module")) {
		armorModule = droidComponent->getAttributeValue("armor_module");
	}
}
void DroidHarvestModuleDataComponent::copy(BaseDroidModuleComponent* other){

	DroidHarvestModuleDataComponent* otherModule = cast<DroidHarvestModuleDataComponent*>(other);
	if( otherModule == NULL )
		return;

	harvestBonus = otherModule->harvestBonus;

	// Save stat in parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL)
		return;
	droidComponent->addProperty("harvest_power", harvestBonus, 0, "exp_effectiveness");
}
void DroidDetonationModuleDataComponent::addToStack(BaseDroidModuleComponent* other) {
	DroidDetonationModuleDataComponent* otherModule = cast<DroidDetonationModuleDataComponent*>(other);
	if (otherModule == NULL)
		return;

	rating = rating + otherModule->rating;
	moduleCount += 1;

	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent != NULL) {
		droidComponent->changeAttributeValue("bomb_level", (float)rating);
		droidComponent->changeAttributeValue("module_count", (float)moduleCount);
	}
}
void DroidDetonationModuleDataComponent::copy(BaseDroidModuleComponent* other) {
	DroidDetonationModuleDataComponent* otherModule = cast<DroidDetonationModuleDataComponent*>(other);
	if (otherModule == NULL)
		return;

	rating = otherModule->rating;
	moduleCount = 1;

	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent != NULL) {
		droidComponent->addProperty("bomb_level", (float)rating, 0, "exp_effectiveness");
		droidComponent->addProperty("module_count", (float)moduleCount, 0, "hidden", true);
		droidComponent->addProperty("module_init", 0, 0, "hidden", true);
	}
}
void DroidArmorModuleDataComponent::copy(BaseDroidModuleComponent* other) {

	DroidArmorModuleDataComponent* otherModule = cast<DroidArmorModuleDataComponent*>(other);
	if (otherModule == NULL)
		return;

	armorModule = otherModule->armorModule;

	// Save stat in parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL)
		return;

	droidComponent->addProperty("armor_module", armorModule, 0, "exp_effectiveness");
}
void DroidHarvestModuleDataComponent::addToStack(BaseDroidModuleComponent* other){

	DroidHarvestModuleDataComponent* otherModule = cast<DroidHarvestModuleDataComponent*>(other);
	if( otherModule == NULL )
		return;

	harvestBonus = harvestBonus + otherModule->harvestBonus;

	// Save stat in parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL)
		return;
	droidComponent->changeAttributeValue( "harvest_power", harvestBonus);

}
void DroidStimpackModuleDataComponent::initialize(DroidObject* droid) {
	// grab the crafted components in this module and remove then
	// then change capacity to the new capacity so we store the stims directly in the component.
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL) {
		info("droidComponent was null");
		return;
	}
	
	//This will instantiate the crafted_components slotted container and satchel if they do not exist
	ManagedReference<SceneObject*> satchel = droidComponent->getCraftedComponentsSatchel();
	if (satchel != NULL) {
		satchel->setContainerVolumeLimit(capacity);
	}

	
}
void DroidHarvestModuleDataComponent::initializeTransientMembers() {

	// Pull module stat from parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL) {
		info("droidComponent was null");
		return;
	}

	if( droidComponent->hasKey( "harvest_power") ){
		harvestBonus = droidComponent->getAttributeValue( "harvest_power");
	}
	else{
		info( "harvest_power attribute not found" );
	}
	harvestTargets.removeAll(0,10);
}
void DroidArmorModuleDataComponent::addToStack(BaseDroidModuleComponent* other) {

	DroidArmorModuleDataComponent* otherModule = cast<DroidArmorModuleDataComponent*>(other);
	if (otherModule == NULL)
		return;

	armorModule = armorModule + otherModule->armorModule;

	// Save stat in parent sceno
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL)
		return;

	// Attribute should have already been created in copy method
	if (!droidComponent->changeAttributeValue( "armor_module", armorModule)) {
		info( "addToStack updateAttributeValue failed");
		return;
	}
}
void DroidDetonationModuleDataComponent::initialize(DroidObject* droid) {
	if (droid->getSpecies() == DroidObject::MSE) {
		mseDroid = true;
	}

	// ensure state on init
	started = false;
	initialized = false;

	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL) {
		info("droidComponent was null");
		return;
	}

	if (droidComponent->hasKey("module_init")) {
		droidComponent->changeAttributeValue("module_init", (float)0);
	} else {
		droidComponent->addProperty("module_init", 0, 0, "hidden", true);
	}
}
void DroidStimpackModuleDataComponent::countUses() {
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
	if (droidComponent == NULL) {
		info("droidComponent was null");
		return;
	}

	DroidObject* droid = getDroidObject();
	if (droid == NULL) {
		return ;
	}

	Locker dlock(droid);

	ManagedReference<SceneObject*> craftingComponents = droidComponent->getSlottedObject("crafted_components");
	if (craftingComponents == NULL) {
		return;
	}

	SceneObject* satchel = craftingComponents->getContainerObject(0);
	if (satchel == NULL) {
		return;
	}

	loaded = 0;

	for (int i = 0; i < satchel->getContainerObjectsSize(); ++i) {
		ManagedReference<SceneObject*> item = satchel->getContainerObject(i);
		if (!item->isPharmaceuticalObject())
			continue;

		PharmaceuticalObject* pharma = item.castTo<PharmaceuticalObject*>();

		if (pharma->isStimPack())
			loaded += pharma->getUseCount();
	}
}
void DroidStimpackModuleDataComponent::initialize(CreatureObject* droid) {
    // grab the crafted components in this module and remove then
    // then change capacity to the new capacity so we store the stims directly in the component.
    DroidComponent* droidComponent = cast<DroidComponent*>(getParent());
    if (droidComponent == NULL) {
        info("droidComponent was null");
        return;
    }
    droidComponent->dropSlottedObject("crafted_components");
    ManagedReference<SceneObject*> craftingComponents = droidComponent->getSlottedObject("crafted_components");
    if(craftingComponents == NULL) {
        // create the satchel and container as it would not be present as this object doesnt use components.
        ManagedReference<SceneObject*> craftingComponentsSatchel = NULL;
        String craftingComponentsPath = "object/tangible/crafting/crafting_components_container.iff";
        craftingComponents = droidComponent->getZoneServer()->createObject(craftingComponentsPath.hashCode(), 1);
        craftingComponents->removeAllContainerObjects();
        craftingComponents->setSendToClient(false);
        droidComponent->transferObject(craftingComponents, 4, false);
        Locker locker(craftingComponents);
        craftingComponents->setContainerDefaultDenyPermission(ContainerPermissions::OPEN + ContainerPermissions::MOVEIN + ContainerPermissions::MOVEOUT + ContainerPermissions::MOVECONTAINER);
        craftingComponents->setContainerDefaultAllowPermission(0);
        craftingComponents->setContainerDenyPermission("owner", ContainerPermissions::OPEN + ContainerPermissions::MOVEIN + ContainerPermissions::MOVEOUT + ContainerPermissions::MOVECONTAINER);
        craftingComponents->setContainerDenyPermission("admin", ContainerPermissions::OPEN + ContainerPermissions::MOVEIN + ContainerPermissions::MOVEOUT + ContainerPermissions::MOVECONTAINER);
        craftingComponents->setContainerAllowPermission("owner", 0);
        craftingComponents->setContainerAllowPermission("admin", 0);
        craftingComponents->setContainerInheritPermissionsFromParent(false);
        locker.release();

        String craftingComponentsSatchelPath = "object/tangible/hopper/crafting_station_hopper/crafting_station_ingredient_hopper_large.iff";
        craftingComponentsSatchel = droidComponent->getZoneServer()->createObject(craftingComponentsSatchelPath.hashCode(), 1);
        Locker locker2(craftingComponentsSatchel);
        craftingComponentsSatchel->setContainerVolumeLimit(capacity);
        craftingComponentsSatchel->setContainerInheritPermissionsFromParent(false);
        craftingComponentsSatchel->setContainerDefaultDenyPermission(ContainerPermissions::OPEN + ContainerPermissions::MOVEIN + ContainerPermissions::MOVEOUT + ContainerPermissions::MOVECONTAINER);
        craftingComponentsSatchel->setContainerDefaultAllowPermission(0);
        craftingComponentsSatchel->setContainerAllowPermission("admin", ContainerPermissions::OPEN);
        craftingComponentsSatchel->setContainerDenyPermission("admin", ContainerPermissions::MOVEIN + ContainerPermissions::MOVEOUT + ContainerPermissions::MOVECONTAINER);
        craftingComponentsSatchel->setContainerAllowPermission("owner", 0);
        craftingComponentsSatchel->setContainerDenyPermission("owner", ContainerPermissions::OPEN + ContainerPermissions::MOVEIN + ContainerPermissions::MOVEOUT + ContainerPermissions::MOVECONTAINER);
        craftingComponentsSatchel->sendTo(droid, true);
        craftingComponents->transferObject(craftingComponentsSatchel, -1, false);
    }
}
void DroidStimpackModuleDataComponent::handleInsertStimpack(CreatureObject* player, StimPack* pack) {
	// we need to send the invalid stimpack message just where is a good question
	countUses();

	if (player == NULL)
		return;

	if (!player->hasSkill("science_medic_ability_04")) {
		return;
	}

	ManagedReference<DroidObject*> droid = getDroidObject();
	if (droid == NULL) {
		return;
	}

	if (pack == NULL) {
		player->sendSystemMessage("@pet/droid_modules:invalid_stimpack");
		return;
	}

	if (!pack->isClassA()) {
		player->sendSystemMessage("@pet/droid_modules:invalid_stimpack");
		return;
	}

	if (droid->getLinkedCreature().get() != player) {
		return;
	}

	// we have the player and the stim to add to ourselves.
	// code should goes as follow, count total use of all stims, then deduct amount form capacity
	DroidComponent* droidComponent = cast<DroidComponent*>(getParent());

	if (droidComponent == NULL) {
		return;
	}

	ManagedReference<SceneObject*> craftingComponents = droidComponent->getSlottedObject("crafted_components");

	if (craftingComponents == NULL) {
		return;
	}

	SceneObject* satchel = craftingComponents->getContainerObject(0);

	if (satchel == NULL) {
		return;
	}

	int allowedAmount = capacity - loaded;

	if (allowedAmount <= 0) {
		player->sendSystemMessage("@pet/droid_modules:stimpack_capacity_full");
		return;
	}

	Locker plocker(pack);

	int amountOnStim = pack->getUseCount();
	StimPack* targetStim = compatibleStimpack(pack->getEffectiveness());

	if (targetStim != NULL) {
		Locker tlocker(targetStim);

		if (allowedAmount > amountOnStim) {
			targetStim->setUseCount(targetStim->getUseCount() + amountOnStim, true);
			pack->decreaseUseCount(pack->getUseCount());
		} else {
			targetStim->setUseCount(targetStim->getUseCount() + allowedAmount, true);
			pack->decreaseUseCount(allowedAmount);
		}
	} else {
		// can we take it all?
		if (allowedAmount > amountOnStim) {
			pack->destroyObjectFromWorld(true);
			// transfer to the droid and broadcast, then send the satchel to the player
			satchel->transferObject(pack, -1, true);
			satchel->broadcastObject(pack, true);
			pack->sendTo(player, true);
			droid->sendTo(player, true);
			player->sendSystemMessage("@pet/droid_modules:stimpack_loaded");
		} else {
			// we cant load it all so split the diff
			StimPack* newStim = pack->split(allowedAmount);

			if (newStim != NULL) {
				Locker slocker(newStim);
				satchel->transferObject(newStim, -1, true);
				satchel->broadcastObject(newStim, true);
				player->sendSystemMessage("@pet/droid_modules:stimpack_loaded");
			}
		}
	}

	countUses();
}