<?php

use App\EntityClassInitialSetup;
use App\EntityClass;
use Illuminate\Database\Seeder;

/**
 * Class EntityClassesSeeder
 */
class EntityClassesSeeder extends Seeder
{

    protected $knownEntityClasses = [

        // Entities without types
        EntityClassInitialSetup::SERVER,
        EntityClassInitialSetup::RAID,
        EntityClassInitialSetup::TRANSCEIVER,
        EntityClassInitialSetup::SWITCH,
        EntityClassInitialSetup::FAN,
        EntityClassInitialSetup::MODULE,
        EntityClassInitialSetup::POWER_SUPPLY,
        EntityClassInitialSetup::VLAN,

        // Entities with types
        EntityClassInitialSetup::DISC,
        EntityClassInitialSetup::PROCESSOR,
        EntityClassInitialSetup::DISC_CONTROLLER,
        EntityClassInitialSetup::MOTHERBOARD,
        EntityClassInitialSetup::NETWORK_CARD,
        EntityClassInitialSetup::WIFI_AP,

        // New entities
        EntityClassInitialSetup::WIFI_ACCOUNT,
        EntityClassInitialSetup::WIFI_ACCOUNT_LOCATIONS,
        EntityClassInitialSetup::SERVER_USER,
        EntityClassInitialSetup::GROUP_MEMBERSHIP,
        EntityClassInitialSetup::SERVER_GROUP,
        EntityClassInitialSetup::WEB_PAGE,
        EntityClassInitialSetup::INSTITUTE,
        EntityClassInitialSetup::EMPLOYEE,

        // Entity types
        EntityClassInitialSetup::DISC_TYPE,
        EntityClassInitialSetup::PROCESSOR_TYPE,
        EntityClassInitialSetup::DISC_CONTROLLER_TYPE,
        EntityClassInitialSetup::MOTHERBOARD_TYPE,
        EntityClassInitialSetup::NETWORK_CARD_TYPE,
        EntityClassInitialSetup::WIFI_PLATFORM,

        EntityClassInitialSetup::SERVER_TYPE,
        EntityClassInitialSetup::SWITCH_TYPE,
        EntityClassInitialSetup::FAN_TYPE,
        EntityClassInitialSetup::POWER_SUPPLY_TYPE,
        EntityClassInitialSetup::TRANSCEIVER_TYPE,
        EntityClassInitialSetup::MODULE_TYPE
    ];

    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {

        DB::transaction(function () {
            $parentClassIdsInClasses = [];
            $entityTypeClassIdInClasses = [];

            foreach ($this->knownEntityClasses as $entityClassName) {

                // Obtain the definition
                $definition = EntityClassInitialSetup::getEntityDefinition($entityClassName);

                // Just ignore the parameters ..
                if (isset($definition['parameters']))
                    unset($definition['parameters']);

                // Add parent entity class ids for later processing (have to create records first)
                if (isset($definition['parent_class_ids'])) {
                    $parentClassIdsInClasses[$definition['id']] = $definition['parent_class_ids'];
                    unset($definition['parent_class_ids']);
                }

                // Add entity types ids for later processing (have to create records first)
                if (isset($definition['entity_type_class_id']) && $definition['entity_type_class_id'] !== null) {
                    $entityTypeClassIdInClasses[$definition['id']] = $definition['entity_type_class_id'];
                    unset($definition['entity_type_class_id']);
                }

                EntityClass::create($definition);

            }

            // Link related types
            foreach ($entityTypeClassIdInClasses as $entityClassId => $entityTypeClassId) {

                EntityClass::where('id', $entityClassId)->update([
                    'entity_type_class_id' => $entityTypeClassId
                ]);
            }

            // Add parent entity class ids for each entity class .. TODO: Try to add multiple entities to one parent (not 1:1)
            foreach ($parentClassIdsInClasses as $entityClassId => $parentEntityClassIds) {

                // Add parent entity class ids
                foreach ($parentEntityClassIds as $parentEntityClassId => $limitingConstrains) {
                    $parentMustNotHaveParent = false;
                    if (is_array($limitingConstrains)) {
                        foreach ($limitingConstrains as $pivotConstraint) {
                            switch ($pivotConstraint) {
                                case EntityClass::PARENT_MUST_NOT_HAVE_PARENT_CONSTRAINT:
                                    $parentMustNotHaveParent = true;
                            }
                        }
                    } else {
                        // The value is actually stored without specifying the key .. so it's this :)
                        $parentEntityClassId = $limitingConstrains;
                    }

                    $this->addParentEntityClass($entityClassId, $parentEntityClassId, $parentMustNotHaveParent);
                }

            }

        });
    }


    /**
     * @param integer $childEntityClassId
     * @param integer $parentEntityClassId
     * @param bool $parentMustNotHaveParent
     */
    protected function addParentEntityClass($childEntityClassId, $parentEntityClassId, $parentMustNotHaveParent = false)
    {

        $parentEntityClasses = DB::table('possible_parent_classes');

        // Set RAID as the only possible parent entity type
        $parentEntityClasses->updateOrInsert([
            'child_entity_class_id' => $childEntityClassId,
            'parent_entity_class_id' => $parentEntityClassId,
            'parent_must_not_have_parent' => $parentMustNotHaveParent
        ]);
    }
}
