<?php

require_once(BASE."public/api/model/BaseModel.php");

class PlatformModel extends BaseModel
{

    public function __construct()
    {
        parent::__construct();
    }

    /**
    * check for valid platform
    * and save data to database
    */
    public function insertPlatform($platform)
    {
        $response = array();
        if ($this->isValidPlatform($platform))
        {
            $response_from_db = $this->savePlatformToDB($platform);
            if ($response_from_db['status'] == 'success')
            {
                $response =
                    array('status' => 'success',
                          'statusCode' => 200,
                          'data' => array('public_key'     => $response_from_db['data']['public_key'],
                                          'uuid'           => $this->getOwnUUID(),
                                          'platform_name'  => $this->getOwnPlatformName(),
                                          'platform_url'   => $this->getOwnPlatformURL(),
                                          'location'       => $this->getOwnPlatformLocation()
                                          ));
                $confirmLink = $this->getOwnPlatformURL().'admin/connection_confirm/'.$platform->uuid;
                $email->email = $this->getOwnPlatformDetail('MarketAdminEmail');
                $email->subject = 'Verbindungsanfrage von '.$platform->name;
                $email->body = $platform->name."(".$platform->url.") möchte sich mit Ihnen verbinden.\n\n"
                    ."Um die Anfrage zu bestätigen, melden Sie sich bei Ihrer Platform an und klicken diesen Link: ".$confirmLink;
                $this->insertEmailToSend($email);
            }
            else
            {
                $response = $response_from_db;
            }
        }
        else
        {
            $response = array('status' => 'error',
                              'statusCode' => 401,
                              'error' => array('type' => 'Unauthorized',
                                               'code' => 'ERR-0401',
                                               'message' => 'Invalid post parameters'));
        }
        return $response;
    }

    protected function savePlatformToDB($platform)
    {
        if ($this->checkUUID($platform->uuid))
        {
            /*
             * generate public/private keypair for new connection
             * and save it to the database as connection to be approved
             */
            $keys = $this->generateKeypair();
            $prefix = $this->get('db_prefix');
            $query = $this->connection->prepare("INSERT INTO ".$prefix."platforms
                                                    (name,
                                                     url,
                                                     location,
                                                     uuid,
                                                     remote_public_key,
                                                     own_public_key,
                                                     private_key,
                                                     modified,
                                                     created_on)
                                                VALUES
                                                    (:name,
                                                     :url,
                                                     :location,
                                                     :uuid,
                                                     :remote_public_key,
                                                     :own_public_key,
                                                     :private_key,
                                                     NOW(),
                                                     NOW())");
            $query->bindParam(':name',              $platform->name,        PDO::PARAM_STR);
            $query->bindParam(':url',               $platform->url,         PDO::PARAM_STR);
            $query->bindParam(':location',          $platform->location,    PDO::PARAM_STR);
            $query->bindParam(':uuid',              $platform->uuid,        PDO::PARAM_STR);
            $query->bindParam(':remote_public_key', $platform->public_key,  PDO::PARAM_STR);
            $query->bindParam(':own_public_key',    $keys['public_key'],    PDO::PARAM_STR);
            $query->bindParam(':private_key',       $keys['private_key'],   PDO::PARAM_STR);

            $response = array();
            if ($query->execute() && $query->rowCount() > 0)
            {
                $platform_id = $this->getPlatformIDByUUID($platform->uuid);
                $this->insertCategoryConnections('send',$platform->receive,$platform_id,'cat2');
                $this->insertCategoryConnections('receive',$platform->send,$platform_id,'cat2');
                $response = array('status' => 'success',
                                  'statusCode' => 200,
                                  'data' => array('public_key' => $keys['public_key']));
            }
            else
            {
                $response = array('status' => 'error',
                                  'statusCode' => 500,
                                  'error' => array('type' => 'Internal Server Error',
                                                   'code' => 'ERR-0500',
                                                   'message' => 'The platform could not be saved'));
            }
            return $response;
        }
        else
        {
            /* A Platform with the same UUID is already in the Database.
             * In the unlikely event that a connection request has been made
             * but the answer has not been saved, there is a state that we are
             * not handling yet. (until we find a way that doesn't provide a
             * potential attack vector)
             */
            $response = array('status' => 'error',
                              'statusCode' => 500,
                              'error' => array('type' => 'Internal Server Error',
                                               'code' => 'ERR-0500',
                                               'message' => 'Platform already waiting to be connected'));
        }
        return $response;
    }

    private function checkUUID($uuid)
    {
        $prefix = $this->get('db_prefix');
        $query = $this->connection->prepare("SELECT id
                                             FROM ".$prefix."platforms
                                             WHERE uuid = :uuid
                                             LIMIT 1");
        $query->bindParam(':uuid', $uuid, PDO::PARAM_STR);
        $query->execute();
        if ($query->rowCount() > 0)
        {
            $response = false;
        } else {
            $response = true;
        }
        return $response;
    }

    public function confirmPlatform($secure_data)
    {
        if ($this->updateConfirmedPlatform($secure_data->own_uuid) == true)
        {
            $response = array('status' => 'success',
                              'statusCode' => 200,
                              'data' => array('uuid' => $secure_data->own_uuid));
        }
        else
        {
            $response = array('status' => 'error',
                              'statusCode' => 404,
                              'error' => array('type' => 'Not Found',
                                               'code' => 'ERR-0404',
                                               'message' => 'Platform with uuid '
                                               .$secure_data->own_uuid.' not found'));
        }
        return $response;
    }

    public function updatePlatform($secure_data)
    {
        if ($this->updatePlatformData($secure_data) == true)
        {
            $response = array('status' => 'success',
                              'statusCode' => 200,
                              'data' => array('uuid' => $secure_data->own_uuid));
        }
        else
        {
            $response = array('status' => 'error',
                              'statusCode' => 404,
                              'error' => array('type' => 'Not Found',
                                               'code' => 'ERR-0404',
                                               'message' => 'Platform with uuid '
                                               .$secure_data->own_uuid.' not found'));
        }
        return $response;
    }

    private function updatePlatformData($data)
    {
        $prefix = $this->get('db_prefix');
        $query = $this->connection->prepare("UPDATE ".$prefix."platforms
                                            SET name = :name,
                                                location = :location,
                                                short_info = :short_info
                                            WHERE uuid = :uuid
                                            LIMIT 1");
        $query->bindParam(':name',              $data->name,        PDO::PARAM_STR);
        $query->bindParam(':location',          $data->location,    PDO::PARAM_STR);
        $query->bindParam(':short_info',        $data->short_info,  PDO::PARAM_STR);
        $query->bindParam(':uuid',              $data->own_uuid,    PDO::PARAM_STR);
        if ($query->execute() && $query->rowCount() >= 0)
        {
            $platform_id = $this->getPlatformIDByUUID($data->own_uuid);
            $this->insertCategoryConnections('remote_receive',$data->receive,$platform_id,'cat2');
            $this->updateSuccessfulSyncStatus($platform_id);
            return true;
        }
        else
        {
            return false;
        }
    }

    private function insertCategoryConnections($type,$categoryIDs,$platform_id,$cat = 'cat2')
    {
        if (!in_array($type,array('send','receive','remote_receive')))
        {
            return false;
        }
        if (!in_array($cat,array('cat1','cat2','cat3')))
        {
            return false;
        }
        if (in_array($platform_id,array(false,0,'')))
        {
            return false;
        }

        $this->deleteCategoryConnections($type,$platform_id);

        if ($categoryIDs != '')
        {
            $categoryIDsArray = explode(',',rtrim(trim($categoryIDs),','));

            $prefix = $this->get('db_prefix');
            $query = $this->connection->prepare("INSERT INTO ".$prefix."category_platforms
                                                    (".$cat.",
                                                     ".$type.")
                                                 VALUES
                                                    (:cat_id,
                                                     :platform_id)");
            $i = 0;
            foreach ($categoryIDsArray as $cat_id)
            {
                $query->bindParam(':cat_id',        $cat_id,        PDO::PARAM_INT);
                $query->bindParam(':platform_id',   $platform_id,   PDO::PARAM_INT);
                if ($query->execute() && $query->rowCount() > 0)
                {
                    $i++;
                }
            }
            if ($i == count($categoryIDsArray))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return true;
        }
    }

    private function deleteCategoryConnections($type,$platform_id)
    {
        if (!in_array($type,array('send','receive','remote_receive')))
        {
            return false;
        }
        $prefix = $this->get('db_prefix');
            $query = $this->connection->prepare("DELETE
                                                 FROM ".$prefix."category_platforms
                                                 WHERE ".$type." = :platform_id");
        $query->bindParam(':platform_id',   $platform_id,   PDO::PARAM_INT);
        $query->execute();
    }

    private function updateConfirmedPlatform($uuid)
    {
        $prefix = $this->get('db_prefix');
        $query = $this->connection->prepare("UPDATE ".$prefix."platforms
                                            SET status = 3, connected_since = NOW()
                                            WHERE uuid = :uuid AND status = 1
                                            LIMIT 1");
        $query->bindParam(':uuid', $uuid, PDO::PARAM_STR);
        if($query->execute() && $query->rowCount() > 0)
        {
            $success = true;
        }
        else
        {
            if (in_array($this->checkPlatformStatus($uuid),array(2,3)))
            {
                $success = true;
            }
            else
            {
                $success = false;
            }
        }
        return $success;
    }

    private function checkPlatformStatus($uuid)
    {
        $prefix = $this->get('db_prefix');
        $query = $this->connection->prepare("SELECT status
                                            FROM ".$prefix."platforms
                                            WHERE uuid = :uuid
                                            LIMIT 1");
        $query->bindParam(':uuid', $uuid, PDO::PARAM_STR);
        if ($query->execute() && $query->rowCount() > 0)
        {
            $platform = $query->fetch();
            return $platform->status;
        } else {
            return false;
        }
    }

    private function isValidPlatform($platform)
    {
        if (strlen(trim($platform->uuid)) < 38)
            return false;
        else if (strlen(trim($platform->name)) < 3 || trim($platform->name) == '')
            return false;
        else if (strlen(trim($platform->url)) < 10)
            return false;
        else if (strlen(trim($platform->public_key)) < 64)
            return false;
        else
            return true;
    }
}
?>
