<?php

  use Eae\Support\Contracts\ExternalFieldInterface;
  use Eae\Support\Contracts\SavableFieldInterface;

  class AdminContentController extends Controller
  {

    public function __construct()
    {
      $this->beforeFilter('csrf', ['on' => ['post', 'delete']]);
    }


    public function getIndex($type)
    {
      $contentType = ContentTypes::find($type);

      $user = Auth::backend()->user();
      if (!$user->hasPermission("cms.manage")) {
        App::abort(403, Lang::get("http_status.403"));
      }

      return View::make('admin/generic/pages/list', ["contentType" => $contentType]);
    }

    public function postList($type)
    {
      $contentType = ContentTypes::find($type);

      $user = Auth::backend()->user();

      if (!$user->hasPermission("cms.manage")) {
        App::abort(403, Lang::get("http_status.403"));
      }

      $page = Input::get("current");
      $sort = Input::get("sort");
      $search = Input::get("searchPhrase");
      $rowCount = Input::get("rowCount");

      if (empty($sort) && $contentType->isOrderable() && !$contentType->isHierarchic()) {
        $sort = ["position" => "asc"];
      }
      $list = $contentType->toList($page, $rowCount, $sort, $search);

      return Response::json($list);
    }

    public function postCheckSlug()
    {
      $originSlug = Input::get("slug");
      $langId = Input::get("lang");

      if (empty($originSlug) || empty($langId)) {
        return Response::json([
          "error"       => "bad_syntax",
          "description" => "The request is missing the slug"
        ], 400);
      }
      $slug = $this->_generateSlug($originSlug, $langId);

      if ($slug === FALSE) {
        return Response::json([
          "error"       => "invalid",
          "description" => "Impossible to generate this slug"
        ], 400);
      } else {
        return Response::json(["slug" => $slug]);
      }
    }

    private function _generateSlug($originSlug, $langId)
    {
      $originSlug = urlize($originSlug);
      $slug = $originSlug;

      $slugCounter = 1;
      while (WebsiteObject::hasSlug($slug, $langId) && $slugCounter <= 6000) {
        $slug = $originSlug . "-" . $slugCounter;
        $slugCounter++;
      }

      if ($slugCounter == 6000) {
        return FALSE;
      } else {
        return $slug;
      }
    }

    public function getFormTemplate($type, $parentId)
    {
      if (!is_numeric($parentId)) {
        App::abort(404);
      }

      $contentType = ContentTypes::find($type);

      if (!$contentType->userHasPermission()) {
        App::abort(403, Lang::get("http_status.403"));
      }

      $parentData = $contentType->getParent();

      if (empty($parentData)) {
        App::abort(404, Lang::get("http_status.404"));
      }
      $modelType = $contentType->getModelType();
      $model = $modelType::where($parentData["field"], $parentId)->first();

      if (empty($model)) {
        $model = $this->_insertFormTemplate($contentType, $parentId);
      }
      $url = "/admin/content/form/{$type}/{$model->id}/{$parentId}";


      return Redirect::to($url);
    }

    private function _insertFormTemplate($contentType, $parentId)
    {
      $loggedUser = Auth::backend()->user();
      $modelType = $contentType->getModelType();
      $model = new $modelType;

      $parentData = $contentType->getParent();
      $parentContentType = ContentTypes::find($parentData["contentType"]);
      $parentModelType = $parentContentType->getModelType();
      $parentModel = $parentModelType::find($parentId);
      $fkName = $parentModel->getForeignKey();

      if (empty($parentModel)) {
        App::abort(404);
      }
      DB::beginTransaction();

      try {
        $model->$fkName = $parentId;
        $model->backend_user_id = $loggedUser->id;
        $model->save();

        $languageModels = $model->languages;
        $languageModelType = $model->languages()->getRelated();

        foreach ($parentModel->languages as $parentLangModel) {
          $languageModel = new $languageModelType;
          $languageModel->language_id = $parentLangModel->language_id;
          $languageModel->title = $parentLangModel->title;
          $languageModels->add($languageModel);
        }

        $model->languages()->saveMany($languageModels->all());

        $websiteObjects = $model->websites;
        $parentWebsiteObject = $parentModel->websites->first();

        $websiteObject = new WebsiteObject;
        $websiteObject->content_type = $contentType->getType();

        $slug = $parentWebsiteObject->slug . "-conf-" . $parentWebsiteObject->id;
        $websiteObject->slug = $slug;
        $websiteObject->status = $parentWebsiteObject->status;
        $websiteObjects->add($websiteObject);

        $model->websites()->saveMany($websiteObjects->all());

        foreach ($parentModel->languages as $langModel) {
          $woLang = new WebsiteObjectLanguage ();
          $woLang->website_object_id = $websiteObject->id;
          $woLang->wo_language_id = $langModel->language_id;
          $woLang->lang_slug = $slug;
          $woLang->lang_uri = NULL;

          $woLang->save();
        }

        DB::commit();
      } catch (Exception $e) {
        DB::rollback();
        Log::error($e);
        throw($e);
      }

      return $model;
    }

    public function getForm($type, $id = FALSE, $parentId = FALSE, $parentContentType = FALSE, $parentFieldName = FALSE)
    {

      $contentType = ContentTypes::find($type);

      if (!$contentType->userHasPermission()) {
        App::abort(403, Lang::get("http_status.403"));
      }

      $parentData = $contentType->getParent();
      //var_dump($parentData); die;
      if ($parentContentType && $parentFieldName) {
        $parentType = ContentTypes::find($parentContentType);
        $parentField = $parentType->getFields()->find($parentFieldName);
        if (!$parentField || $parentField->getObjectType() != $type) {
          App::abort(404);
        }

        $parentData = [
          'field'       => $parentFieldName,
          'contentType' => $parentContentType
        ];
      }

      $modelType = $contentType->getModelType();

      if (!empty($id)) {
        if (!is_numeric($id)) {
          App::abort(404);
        }

        $model = $modelType::find($id);

        if (empty($model)) {
          App::abort(404);
        }

      } else {
        if (!$contentType->userHasPermission()) {
          App::abort(403, Lang::get("http_status.403"));
        }

        $modelType = $contentType->getModelType();
        $model = new $modelType;
      }
      if (!$model->exists && (!empty($parentId) && empty($parentData)) ||
        (empty($parentId) && !empty($parentData))
      ) {
        App::abort(400, Lang::get("http_status.400"));
      }

      if (Request::ajax()) {
        return View::make('admin/generic/components/form',
          [
            "model"       => $model,
            "contentType" => $contentType,
            "parentId"    => $parentId]);
      } else {
        return View::make('admin/generic/pages/form',
          [
            "model"       => $model,
            "contentType" => $contentType,
            "parentId"    => $parentId]);
      }


    }

    /**
     * Util to reconstruct all uris for a given content type
     *
     * @param mixed $type
     */
    public function getUpdateUris($type)
    {
      $contentType = ContentTypes::find($type);

      if (!$contentType->userHasPermission()) {
        App::abort(403, Lang::get("http_status.403"));
      }

      if (!$contentType->getBaseUri()) {
        App::abort(500, "No base URI configured for this content type");
      }

      $modelType = $contentType->getModelType();
      $models = $modelType::full()->get();

      foreach ($models as $model) {
        $websiteObjects = $model->websites;
        $websiteObject = $websiteObjects->findByWebsite($website->id);
        $this->_updateUri($websiteObject, $contentType);
      }

      echo 'Success!';
    }

    private function _updateUri($websiteObject, $contentType, $save = TRUE)
    {
      $uri = $contentType->getBaseUri();
      $languages = getAvailableLanguages();
      $defaultLang = getDefaultLanguage();

      $defaultUri = "";
      if ($websiteObject->parent) {
        $parent = $websiteObject->parent;

        foreach ($languages as $langCode => $lang) {
          $parentWoLang = $parent->languages->findByLocale($langCode);
          $woLang = $websiteObject->languages->findByLocale($langCode);
          $woLang->lang_uri = $parentWoLang->lang_uri . '/' . $woLang->lang_slug;
          if ($defaultLang == $langCode) {
            $defaultUri = $woLang->lang_uri;
          }
          if ($save) {
            $woLang->save();
          }
        }
      } else {
        if ($websiteObject->slug == 'home') {
          $defaultUri = '/';
          foreach ($languages as $langCode => $lang) {
            $woLang = $websiteObject->languages->findByLocale($langCode);
            $woLang->lang_uri = $defaultUri;
            if ($save) {
              $woLang->save();
            }
          }
        } else {
          foreach ($languages as $langCode => $lang) {
            $woLang = $websiteObject->languages->findByLocale($langCode);

            if (is_array($uri)) {
              $uriLang = $uri[ $langCode ];
            } else {
              $uriLang = $uri;
            }
            $woLang->lang_uri = $uriLang . '/' . $woLang->lang_slug;
            if ($defaultLang == $langCode) {
              $defaultUri = $woLang->lang_uri;
            }
            if ($save) {
              $woLang->save();
            }
          }
        }
      }
      $websiteObject->uri = $defaultUri;
      if ($save) {
        $websiteObject->save();
      }

      if ($websiteObject->website_object_id) {
        $children = $websiteObject->children;
        foreach ($children as $child) {
          $this->_updateUri($child, $contentType, $save);
        }
      }
    }

    public function postForm($type, $id = FALSE, $parentId = FALSE, $parentContentType = FALSE, $parentFieldName = FALSE)
    {

      $contentType = ContentTypes::find($type);

      if (!$contentType->userHasPermission()) {
        App::abort(403, Lang::get("http_status.403"));
      }

      $loggedUser = Auth::backend()->user();
      if (!empty($id)) {
        if (!is_numeric($id)) {
          App::abort(404);
        }

        $modelType = $contentType->getModelType();
        $model = $modelType::find($id);

        if (empty($model)) {
          App::abort(404);
        }
      } else {
        $modelType = $contentType->getModelType();
        $model = new $modelType;
      }

      $parentData = $contentType->getParent();
      $hasPivot = FALSE;

      if ($parentContentType && $parentFieldName) {
        $parentType = ContentTypes::find($parentContentType);
        $parentField = $parentType->getFields()->find($parentFieldName);
        if (!$parentField || $parentField->getObjectType() != $type) {
          App::abort(404);
        }

        $parentData = [
          'field'       => $parentFieldName,
          'contentType' => $parentContentType
        ];
        $hasPivot = TRUE;
      }

      if (!$model->exists && (!empty($parentId) && empty($parentData)) ||
        (empty($parentId) && !empty($parentData))
      ) {
        App::abort(400, Lang::get("http_status.400"));
      }


      $validation = $contentType->getValidation(!$model->exists);

      $validator = Validator::make(
        $validation["values"],
        $validation["rules"]

      );

      $validator->setAttributeNames($validation["labels"]);

      $languages = getAvailableLanguages();
      foreach ($languages as $langCode => $lang) {
        $originSlug = $validation["values"]["lang_slug"][ $langCode ];
        if ($model->exists && $model->website_object_id) {
          $woLang = WebsiteObjectLanguage::where('website_object_id', $model->website_object_id)
            ->where('wo_language_id', $langCode)
            ->first();
          if ($woLang && $woLang->lang_slug == $originSlug) {
            continue;
          }
        }
        $slug = $this->_generateSlug($originSlug, $langCode);
        $validation["values"]["lang_slug"][ $langCode ] = ($slug ? $slug : '');
      }
      if ($validator->fails()) {
        Input::flash();
        RequestContext::set("errors", $validator->getMessageBag());
        View::share("errors", $validator->getMessageBag());

        if (Request::ajax()) {
          return View::make('admin/generic/components/form',
            [
              "model"       => $model,
              "contentType" => $contentType,
              "parentId"    => $parentId]);
        } else {
          return View::make('admin/generic/pages/form',
            [
              "model"       => $model,
              "contentType" => $contentType,
              "parentId"    => $parentId]);
        }
      }

      if (!empty($parentData) && !$model->exists && !$hasPivot) {
        $parentField = $parentData["field"];
        $model->$parentField = $parentId;
      }

      $modelFields = $contentType->getFields()->getSingleLanguageFields();

      foreach ($modelFields as $field) {
        if ($field->isRelationField() || $field instanceof ExternalFieldInterface) {
          continue;
        }
        $fieldName = $field->getName();
        if ($field instanceof SavableFieldInterface) {
          $field->save($model, $validation["values"][ $fieldName ]);
        } else {
          $model->$fieldName = $validation["values"][ $fieldName ];
        }
      }

      DB::beginTransaction();

      try {
        if (!$model->exists) {
          $model->backend_user_id = $loggedUser->id;
        }
        if ($model->exists || !$hasPivot) {
          $model->save();
        } else {
          $parentContentType = ContentTypes::find($parentData["contentType"]);
          $parentModelType = $parentContentType->getModelType();
          $parentModel = $parentModelType::find($parentId);
          $parentModel->$parentData["field"]()->save($model);
        }

        $languageFields = $contentType->getFields()->getMultiLanguageFields();
        $languageModels = $model->languages;

        foreach ($languageFields as $field) {
          if ($field->isRelationField() || $field instanceof ExternalFieldInterface) {
            continue;
          }

          $fieldName = $field->getName();
          $values = $validation["values"][ $fieldName ];
          $languageModelType = $model->languages()->getRelated();

          foreach ($values as $languageId => $value) {
            $languageModel = $languageModels->findByLocale($languageId);
            if (empty($languageModel)) {
              $languageModel = new $languageModelType;
              $languageModel->language_id = $languageId;
              $languageModels->add($languageModel);
            }

            if ($field instanceof SavableFieldInterface) {
              $field->save($languageModel, $value);
            } else {
              $languageModel->$fieldName = $value;
            }

          }
        }

        $model->languages()->saveMany($languageModels->all());
        $websiteObjects = $model->websites;

        $websiteObject = $websiteObjects->first();

        if (empty($websiteObject)) {
          $websiteObject = new WebsiteObject;
          $websiteObject->content_type = $contentType->getType();

          if ($contentType->isOrderable()) {
            $position = WebsiteObject::maxPosition(
              class_basename($model));
            if (empty($position)) {
              $position = 0;
            }
            $websiteObject->position = $position + 1;
          }

          $websiteObjects->add($websiteObject);
          foreach ($languageModels as $lang) {
            $woLang = new WebsiteObjectLanguage();
            $woLang->wo_language_id = $lang->language_id;

            $websiteObject->languages->add($woLang);
          }
        }

        $defaultLang = getDefaultLanguage();
        foreach ($languageModels as $lang) {
          $woLang = $websiteObject->languages->findByLocale($lang->language_id);
          if (isset($validation["values"]["lang_slug"][ $lang->language_id ])) {
            $woLang->lang_slug = $validation["values"]["lang_slug"][ $lang->language_id ];
          } else {
            $woLang->lang_slug = $validation["values"]["lang_slug"][ $defaultLang ];
          }

          if ($defaultLang == $lang->language_id) {
            $websiteObject->slug = $validation["values"]["lang_slug"][ $lang->language_id ];
          }
        }
        $websiteObject->status = $validation["values"]["status"];
        $websiteObject->template = $validation["values"]["template"];

        if ($contentType->hasTemplate() ||
          $contentType->getBaseUri() != FALSE
        ) {
          $this->_updateUri($websiteObject, $contentType, FALSE);
        }

        $model->websites()->saveMany($websiteObjects->all());

        foreach ($websiteObjects as $websiteObject) {
          $websiteObject->languages()->saveMany($websiteObject->languages->all());
        }

        if ($contentType->isSearchable()) {
          $searchContents = $contentType->getSearchStructure($model);

          foreach ($websiteObjects as $websiteObject) {
            $websiteObject->searches()->delete();
            if ($websiteObject->status == 'draft') {
              continue;
            }

            if (isset($searchContents)) {
              foreach ($searchContents as $locale => $searchContent) {
                $search = new WebsiteObjectSearch($searchContent);
                $search->language_id = $locale;
                $websiteObject->searches()->save($search);
              }
            }
          }
        } else {
          $websiteObject->searches()->delete();
        }

        $relationFields = $contentType->getFields()->getRelationFields();

        foreach ($relationFields as $field) {
          $fieldName = $field->getName();
          if (isset($validation["values"][ $fieldName ])) {
            $field->save($model, $validation["values"][ $fieldName ]);
          }
        }

        DB::commit();
      } catch (Exception $e) {
        DB::rollback();
        Log::error($e);
        throw($e);
      }

      $redirectUrl = Request::path();
      if ($id === FALSE) {
        $redirectUrl .= "/" . $model->id;
      }
      Session::forget("_old_input");
      if (Request::ajax()) {
        return Response::json([
          "id"                => $model->id,
          "title"             => $model->title,
          "website_object_id" => $model->website_object_id
        ]);
      } else {
        //If has template and has template configuration, jumps to it
        if ($contentType->hasTemplate()) {
          $objectTemplate = $contentType->getTemplates()[ $websiteObject->template ];
          if (isset($objectTemplate['contentType'])) {
            $contentType = ContentTypes::find($objectTemplate['contentType']);
            $parentData = $contentType->getParent();
            if (empty($parentData)) {
              App::abort(404, Lang::get("http_status.404"));
            }
            $modelType = $contentType->getModelType();
            $configModel = $modelType::where($parentData["field"], $model->id)->first();

            if (!$configModel) {
              $redirectUrl = 'admin/content/form-template/' . $objectTemplate['contentType'] . '/' . $model->id;

              return Redirect::to($redirectUrl);
            }
          }
        }

        return Redirect::to($redirectUrl)->withMessage(Lang::get("backend.save_success"));
      }
    }

    public function deleteIndex()
    {
      $type = Input::get("type");
      $id = Input::get("id");
      $fullDelete = Input::get("fullDelete", FALSE);

      if (empty($type) || empty($id) || !is_numeric($id)) {
        return Response::json([
          "error"       => "bad_syntax",
          "description" => Lang::get("http_status.400")],
          400);
      }

      $contentType = ContentTypes::find($type);

      if (!$contentType->userHasPermission()) {
        App::abort(403, Lang::get("http_status.403"));
      }

      $modelType = $contentType->getModelType();

      $model = $modelType::find($id);

      if (empty($model)) {
        return Response::json([
          "error"       => "not_found",
          "description" => Lang::get("http_status.404")],
          404);
      }

      DB::beginTransaction();

      try {
        $model->delete();
        WebsiteObject::where("object_id", $id)
          ->where("object_type", $modelType)
          ->delete();
        $this->cleanWebsiteObjects();
        $this->_cleanWebsiteObjectSearches();
        DB::commit();
      } catch (Exception $e) {
        DB::rollback();
        Log::error($e);
        App::abort(500);
      }

      return Response::json(["success" => TRUE]);
    }

    /**
     * Cleans the website objects table for objects that got deleted by database
     * foreign key cascade deletes
     *
     */
    protected function cleanWebsiteObjects()
    {
      $contentTypes = ContentTypes::all();

      foreach ($contentTypes as $contentType) {
        $modelType = $contentType->getModelType();
        $model = new $modelType();
        $table = $model->getTable();

        $toDelete = WebsiteObject::where('content_type', $contentType->getType())
          ->whereNotExists(function ($query) use ($table) {
            $query->select(DB::raw(1))
              ->from($table)
              ->whereRaw(WebsiteObject::getTableName() . ".object_id = {$table}.id");
          })->delete();
      }
    }

    protected function _cleanWebsiteObjectSearches()
    {
      DB::table("website_objects_search")
        ->whereNotExists(function ($query) {
          $query->select(DB::raw(1))
            ->from("website_objects")
            ->whereRaw("website_objects_search.website_object_id = website_objects.website_object_id");
        })->delete();
    }

    public function getOrder($type)
    {
      $contentType = ContentTypes::find($type);

      if (!$contentType->userHasPermission()) {
        App::abort(403, Lang::get("http_status.403"));
      }

      if ($contentType->isHierarchic()) {
        $entries = $contentType->toStructuredList();
      } else {
        $entries = $contentType->toList(NULL, NULL, ['position' => 'asc'])->all();
      }

      return View::make('admin/generic/pages/order', [
        "contentType" => $contentType,
        "entries"     => $entries
      ]);
    }

    public function postOrder($type)
    {
      $contentType = ContentTypes::find($type);


      if (!$contentType->userHasPermission()) {
        App::abort(403, Lang::get("http_status.403"));
      }

      $modelType = $contentType->getModelType();

      $newOrder = Input::get('content_order');
      $newOrder = json_decode($newOrder);

      if (!$newOrder || !is_array($newOrder)) {
        App::abort(400);
      }

      DB::beginTransaction();
      try {
        $counter = 0;
        $this->_saveOrder($newOrder, $contentType->getModelType(), $counter);
        DB::commit();
      } catch (Exception $e) {
        DB::rollback();
        Log::error($e);
        App::abort(500);
      }

      $redirectUrl = 'admin/content/index/' . $type;
      if (Request::ajax()) {
        return Response::json(["message" => "OK"]);
      } else {
        return Redirect::to($redirectUrl)->withMessage(Lang::get("backend.save_success"));
      }

    }

    private function _saveOrder($orderTree, $objectType, &$i, $parent = NULL)
    {
      foreach ($orderTree as $orderItem) {
        $i++;
        if (!is_numeric($orderItem->id)) {
          App::abort(400);
        }
        $websiteObject = WebsiteObject::find($orderItem->id);
        if (empty($websiteObject) || $websiteObject->object_type !== $objectType) {
          App::abort(400);
        }
        $websiteObject->position = $i;
        if ($parent) {
          $websiteObject->parent_id = $parent->id;
          if ($websiteObject->object_type == 'Entry') {
            $websiteObject->uri = $websiteObject->parent->uri . '/' . $websiteObject->slug;
          }
        } else {
          if ($websiteObject->object_type == 'Entry') {
            $websiteObject->uri = '/' . ($websiteObject->slug == 'home' ? '' : $websiteObject->slug);
          }
          $websiteObject->parent_id = NULL;
        }
        $websiteObject->save();

        if (isset($orderItem->children)) {
          $this->_saveOrder($orderItem->children, $objectType, $i, $orderItem);
        }
      }
    }

    public function postAutoComplete($type)
    {
      $contentType = ContentTypes::find($type);

      $user = Auth::backend()->user();
      if (!$user->hasPermission("cms.manage")) {
        App::abort(403, Lang::get("http_status.403"));
      }

      $searchTerm = Input::get('searchTerm', '');
      $cleanedSearchTerm = Formatter::transformItem($searchTerm, "strip_tags|xss_clean|trim");

      if (empty($cleanedSearchTerm)) {
        return Response::json([
          "error"       => Config::get("error.not_found"),
          "description" => Lang::get("response.not_found")
        ], 404);
      }


      $results = $contentType->autoComplete($cleanedSearchTerm);

      return Response::json($results, 200);

    }
  }
