<?php

/**
 * Lifestyle Webconsulting GmbH
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is private by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\RestBundle\Controller\MultipleWs\Version1;

use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\View\View;
use JMS\SecurityExtraBundle\Annotation\Secure;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use FOS\RestBundle\Controller\Annotations\NamePrefix;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\FOSRestController;
use Sso\RestBundle\Worker\Worker as Worker;
use JMS\DiExtraBundle\Annotation as DI;
use FOS\RestBundle\Controller\Annotations\Get;
use LifeStyle\Tools\CachingBundle\Annotations\LsCache;

/**
 * Class ScopeController
 *
 * @NamePrefix("api_rest_")
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 * @package    Sso\RestBundle\Controller
 */
class ScopeController extends FOSRestController
{
    /**
     * @DI\Inject("rest_worker_manager")
     * @var Worker
     */
    protected $woM;

    /**
     *
     * *This service gets all objects for the scopes of an user.*
     *
     * #Request (header)
     *
     *      Key                 | Value               | Description
     *      ------------------- | ------------------- | --------------------------------------
     *      username            |  (string)           | your username
     *      useridentifier      |  (string)           | your useridentifier for given username
     *      servicetoken        |  (string)           | your useridentifier for given username
     *
     * ##Request
     *
     * **Request example JSON**
     *
     *          /api/v1/scope/object.json?identifier=YOURIDENTIFIER
     *
     * **Request example XML**
     *
     *          /api/v1/scope/object.xml?identifier=YOURIDENTIFIER
     *
     * ##Response success
     *
     * **Example (header)**
     *
     *          200 OK
     *
     * **Example JSON (body)**
     *
     *          {
     *            "status": "Success",
     *            "trackid": "5c16cec8f4",
     *            "date": "2016-03-22T10:21:02+0100",
     *            "count": "26",
     *            "objects": [
     *              {
     *                "guid": "EA9155A9-A34B-F7B1-C9DC-A00A37B86043",
     *                "referenceId": "S0000034RestWsTest4Updated",
     *                "name": "RestWsTestUpdated",
     *                "created": "2016-02-09T15:19:01+0100",
     *                "updated": "2016-03-22T10:21:03+0100"
     *              },
     *              {
     *                "guid": "69388074-D68A-5DCC-7B41-43826B7DF795",
     *                "referenceId": "S008Updated",
     *                "parentGuid": "16FA40FD-5F4B-4937-F53E-F598471AAFD8",
     *                "name": "ParentObjectTest2",
     *                "created": "2016-02-05T11:16:04+0100",
     *                "updated": "2016-03-22T10:21:00+0100",
     *                "children": [
     *                  {
     *                    "guid": "1ABE53B9-1926-14E0-B77D-1F8FE316263E",
     *                    "referenceId": "S002",
     *                    "parentGuid": "69388074-D68A-5DCC-7B41-43826B7DF795",
     *                    "name": "Object3",
     *                    "created": "2016-02-08T09:53:18+0100",
     *                    "updated": "2016-03-22T10:21:00+0100",
     *                    "children": [
     *                      {
     *                        "guid": "E138F8B4-BCEE-52AC-180E-068D0F4CCC5A",
     *                        "referenceId": "S000131",
     *                        "parentGuid": "1ABE53B9-1926-14E0-B77D-1F8FE316263E",
     *                        "name": "Object 3.1",
     *                        "created": "2016-03-15T15:18:27+0100",
     *                        "updated": "2016-03-22T10:20:59+0100",
     *                        "children": []
     *                      }
     *                    ]
     *                  }
     *                ]
     *              }
     *            ]
     *          }
     *
     * **Example XML (body)**
     *
     *          <?xml version="1.0" encoding="UTF-8"?>
     *            <SsoResponse>
     *              <status><![CDATA[Success]]></status>
     *              <trackid><![CDATA[1838c6f66a]]></trackid>
     *              <date><![CDATA[2016-03-22T10:27:01+0100]]></date>
     *              <count><![CDATA[26]]></count>
     *              <objects>
     *                <guid><![CDATA[EA9155A9-A34B-F7B1-C9DC-A00A37B86043]]></guid>
     *                <referenceId><![CDATA[S0000034RestWsTest4Updated]]></referenceId>
     *                <name><![CDATA[RestWsTestUpdated]]></name>
     *                <created><![CDATA[2016-02-09T15:19:01+0100]]></created>
     *                <updated><![CDATA[2016-03-22T10:27:02+0100]]></updated>
     *              </objects>
     *              <objects>
     *                <guid><![CDATA[69388074-D68A-5DCC-7B41-43826B7DF795]]></guid>
     *                <referenceId><![CDATA[S008Updated]]></referenceId>
     *                <parentGuid><![CDATA[16FA40FD-5F4B-4937-F53E-F598471AAFD8]]></parentGuid>
     *                <name><![CDATA[ParentObjectTest2]]></name>
     *                <created><![CDATA[2016-02-05T11:16:04+0100]]></created>
     *                <updated><![CDATA[2016-03-22T10:26:59+0100]]></updated>
     *                <children>
     *                  <objects>
     *                    <guid><![CDATA[1ABE53B9-1926-14E0-B77D-1F8FE316263E]]></guid>
     *                    <referenceId><![CDATA[S002]]></referenceId>
     *                    <parentGuid><![CDATA[69388074-D68A-5DCC-7B41-43826B7DF795]]></parentGuid>
     *                    <name><![CDATA[Object3]]></name>
     *                    <created><![CDATA[2016-02-08T09:53:18+0100]]></created>
     *                    <updated><![CDATA[2016-03-22T10:26:59+0100]]></updated>
     *                    <children>
     *                      <objects>
     *                        <guid><![CDATA[E138F8B4-BCEE-52AC-180E-068D0F4CCC5A]]></guid>
     *                        <referenceId><![CDATA[S000131]]></referenceId>
     *                        <parentGuid><![CDATA[1ABE53B9-1926-14E0-B77D-1F8FE316263E]]></parentGuid>
     *                        <name><![CDATA[Object 3.1]]></name>
     *                        <created><![CDATA[2016-03-15T15:18:27+0100]]></created>
     *                        <updated><![CDATA[2016-03-22T10:26:58+0100]]></updated>
     *                      </objects>
     *                    </children>
     *                  </objects>
     *                </children>
     *              </objects>
     *            </SsoResponse>
     *
     * ##Response error
     *
     * **Example (header)**
     *
     *          400 Bad Request
     *
     * **Example JSON (body)**
     *
     *          {
     *            "status": "400",
     *            "message": "Bad Request",
     *            "trackid": "983dcc25a1",
     *            "count": "1",
     *            "errors": [
     *              {
     *                "code": "400",
     *                "message": "ErrorCode: No objects found. ErrorRef: os001 ShortMessage: No objects found.",
     *                "exception": "external"
     *              }
     *            ]
     *          }
     *
     *
     * **Example XML (body)**
     *
     *          <?xml version="1.0" encoding="UTF-8"?>
     *            <SsoResponse>
     *              <status><![CDATA[400]]></status>
     *              <message><![CDATA[Bad Request]]></message>
     *              <trackid><![CDATA[4e7cf3cf72]]></trackid>
     *              <count><![CDATA[1]]></count>
     *              <errors>
     *                <error>
     *                  <code><![CDATA[400]]></code>
     *                  <message><![CDATA[ErrorCode: No objects found. ErrorRef: os001 ShortMessage: No objects found.]]></message>
     *                  <exception><![CDATA[external]]></exception>
     *                </error>
     *              </errors>
     *            </SsoResponse>
     *
     * @ApiDoc(
     *  resource=true,
     *  description="secured: get objects for user",
     *  statusCodes={
     *         200="Returned when successful",
     *         400="Returned when an error occured",
     *         401="Unauthorized - Wrong credentials",
     *         403="Returned when the user is not authorized to do this request",
     *         500="Returned on internal server errors"
     *  },
     *  headers={
     *      {"name"="username", "description"="sso username"},
     *      {"name"="useridentifier", "description"="sso useridentifier"},
     *      {"name"="servicetoken", "description"="servicetoken"}
     *  },
     *  tags={
     *      "stable" = "#000",
     *      "cacheable" = "#0A0"
     *  },
     *  views = { "sso-ws-multiple" }
     * )
     * @Get("/v1/sso-ws-multiple/userObject/scope", name="_sso-ws-multiple_v1", options={ "method_prefix" = true })
     * @QueryParam(name="identifier", nullable=false, strict=true, description="any user identifier")
     * @Secure(roles="ROLE_API")
     * @LsCache(cacheTTL=300, keyHeader=true)
     * @param Request $request
     * @return View
     */
    public function getScopeObjectsAction(Request $request)
    {
        $worker = $this->woM->multipleWs()->version1()->scope()->getScopeObjects();
        if (null !== ($errorView = $worker->init($request))) {
            return $errorView;
        }

        // First: get user application attributes.
        $view = $worker->getUserApplicationAttributes($request);

        $objectResponses = [];
        if (200 == $view->getStatusCode()) {
            // Second: get objects for given user application attributes.
            $objectResponseViews = $worker->getObjectsByAttributes($request, $view->getData());

            // Third: merge responses of the ObjectGet requests to have one response.
            foreach ($objectResponseViews as $objectResponseView) {
                $objectResponses[] = $objectResponseView->getData();
            }
            $response = $worker->buildResponse($objectResponses);
        } else {
            // in case of errors we don't actually want to return an error here,
            // but rather a "successful", but empty, result
            $response = $worker->buildResponse($objectResponses);
            $response->setCode('200');
            $response->setScriptTimeSec($view->getData()->getScriptSeconds());
            $response->setTrackId($view->getData()->getTrackId());
            $response->setDate(new \DateTime());
            $response->setCount(0);
        }

        return $response;
    }

    /**
     * *This service gets a treeview for all objects for the scopes of an user.*
     *
     * #Request (header)
     *
     *      Key                 | Value               | Description
     *      ------------------- | ------------------- | --------------------------------------
     *      username            |  (string)           | your username
     *      useridentifier      |  (string)           | your useridentifier for given username
     *      servicetoken        |  (string)           | your useridentifier for given username
     *
     * ##Request
     *
     * **Request example JSON**
     *
     *          /api/v1/sso-ws-multiple/userObject/scopeTreeview.json?identifier=YOURIDENTIFIER
     *
     * **Request example XML**
     *
     *          /api/v1/sso-ws-multiple/userObject/scopeTreeview.xml?identifier=YOURIDENTIFIER
     *
     * ##Response success
     *
     * **Example (header)**
     *
     *          200 OK
     *
     * **Example JSON (body)**
     *
     *         {
     *           "code": 200,
     *           "status": "OK",
     *           "trackId": "898a126cac",
     *           "scriptTimeSec": 15.5685,
     *           "count": "14",
     *           "objects": [
     *             {
     *               "typeName": "Root",
     *               "guid": "d106d322-0b49-4cc5-806f-2638e8e19800",
     *               "referenceId": "S0000001",
     *               "name": "All Sso",
     *               "treeId": "1",
     *               "scopeType": "parent"
     *             },
     *             {
     *               "typeName": "Division",
     *               "guid": "37a21be4-5c6a-4cbd-88bf-de8b6783c561",
     *               "referenceId": "S0000309",
     *               "name": "United Europe",
     *               "treeId": "1.01",
     *               "scopeType": "secondary"
     *             }
     *           ]
     *         }
     *
     * **Example XML (body)**
     *
     *         <?xml version="1.0" encoding="UTF-8"?>
     *         <scopeObjectTreeView>
     *           <code>200</code>
     *           <status><![CDATA[OK]]></status>
     *           <trackId><![CDATA[acde6ceb8c]]></trackId>
     *           <scriptTimeSec>20.4195</scriptTimeSec>
     *           <count><![CDATA[14]]></count>
     *           <objects>
     *             <typeName><![CDATA[Root]]></typeName>
     *             <guid><![CDATA[d106d322-0b49-4cc5-806f-2638e8e19800]]></guid>
     *             <referenceId><![CDATA[S0000001]]></referenceId>
     *             <name><![CDATA[All Sso]]></name>
     *             <treeId><![CDATA[1]]></treeId>
     *             <scopeType><![CDATA[parent]]></scopeType>
     *           </objects>
     *           <objects>
     *             <typeName><![CDATA[Division]]></typeName>
     *             <guid><![CDATA[37a21be4-5c6a-4cbd-88bf-de8b6783c561]]></guid>
     *             <referenceId><![CDATA[S0000309]]></referenceId>
     *             <name><![CDATA[United Europe]]></name>
     *             <treeId><![CDATA[1.01]]></treeId>
     *             <scopeType><![CDATA[secondary]]></scopeType>
     *           </objects>
     *         </scopeObjectTreeView>
     *
     * ##Response error
     *
     * **Example (header)**
     *
     *          400 Bad Request
     *
     * **Example JSON (body)**
     *
     *         {
     *           "code": 400,
     *           "status": "Bad Request",
     *           "trackId": "a605206a8e",
     *           "count": 1,
     *           "errors": [
     *             {
     *               "code": 400,
     *               "status": "Bad Request",
     *               "message": "ErrorCode: u001 ErrorRef: uat011 ShortMessage: Invalid user",
     *               "type": "external",
     *               "exception": "User not found in database",
     *               "debug": "not set"
     *             }
     *           ]
     *         }
     *
     * **Example XML (body)**
     *
     *         <?xml version="1.0" encoding="UTF-8"?>
     *         <response>
     *           <code>400</code>
     *           <status><![CDATA[Bad Request]]></status>
     *           <trackId><![CDATA[44234059e0]]></trackId>
     *           <count>1</count>
     *           <errors>
     *             <error>
     *               <code>400</code>
     *               <status><![CDATA[Bad Request]]></status>
     *               <message><![CDATA[ErrorCode: u001 ErrorRef: uat011 ShortMessage: Invalid user]]></message>
     *               <type><![CDATA[external]]></type>
     *               <exception><![CDATA[User not found in database]]></exception>
     *               <debug><![CDATA[not set]]></debug>
     *             </error>
     *           </errors>
     *         </response>
     *
     * @ApiDoc(
     *  resource="/api/v1/sso-ws-multiple/userObject/scope",
     *  description="secured: get objects treeview for user",
     *  statusCodes={
     *         200="Returned when successful",
     *         400="Returned when an error occured",
     *         401="Unauthorized - Wrong credentials",
     *         403="Returned when the user is not authorized to do this request",
     *         500="Returned on internal server errors"
     *  },
     *
     *  headers={
     *      {"name"="username", "description"="sso username"},
     *      {"name"="useridentifier", "description"="sso useridentifier"},
     *      {"name"="servicetoken", "description"="servicetoken"}
     *  },
     *     parameters={
     *      {"name"="identifier", "dataType"="string", "required"=false, "description"="User Identifier"},
     *  },
     *  tags={
     *      "stable" = "#000",
     *      "cacheable" = "#0A0"
     *  },
     *  views = { "sso-ws-multiple" }
     * )
     * @Get("/v1/sso-ws-multiple/userObject/scopeTreeview", name="_sso-ws-multiple_v1", options={ "method_prefix" = true })
     * @Secure(roles="ROLE_API")
     * @LsCache(cacheTTL=300, keyHeader=true)
     * @param Request $request
     * @return View
     */
    public function getScopeTreeviewObjectsAction(Request $request)
    {

        $worker = $this->woM->multipleWs()->version1()->scope()->getScopeTreeObjects();
        if (null !== ($errorView = $worker->init($request))) {
            return $errorView;
        }
        $userApplicationAttributesView = $worker->getUserApplicationAttributes($request);

        if (200 != $userApplicationAttributesView->getStatusCode()) {
            return $worker->buildResponse([]);
        }

        return $worker->getObjectsByAttributes($request, $userApplicationAttributesView->getData());
    }
}
