From 288ddd2efc765d91389951fe0286caaa0d29f1a0 Mon Sep 17 00:00:00 2001
From: Olivier PEREZ <olivier@olivierperez.fr>
Date: Tue, 23 Dec 2014 00:30:05 +0100
Subject: [PATCH] admin: Add availability to add a slot to a poll

---
 app/classes/Framadate/FramaDB.php             |  19 ++-
 .../Framadate/Services/AdminPollService.php   | 112 +++++++++++++++---
 app/classes/Framadate/Utils.php               |   2 +-
 3 files changed, 117 insertions(+), 16 deletions(-)

diff --git a/app/classes/Framadate/FramaDB.php b/app/classes/Framadate/FramaDB.php
index 2e03d577..aab3fc1a 100644
--- a/app/classes/Framadate/FramaDB.php
+++ b/app/classes/Framadate/FramaDB.php
@@ -48,6 +48,18 @@ class FramaDB {
         $this->pdo->commit();
     }
 
+    function rollback() {
+        $this->pdo->rollback();
+    }
+
+    function errorCode() {
+        return $this->pdo->errorCode();
+    }
+
+    function errorInfo() {
+        return $this->pdo->errorInfo();
+    }
+
     function query($sql) {
         return $this->pdo->query($sql);
     }
@@ -63,7 +75,7 @@ class FramaDB {
     }
 
     function updatePoll($poll) {
-        $prepared = $this->prepare('UPDATE sondage SET title=?, admin_mail=?, comment=?, active=?, editable=? WHERE sondage.poll_id = ?');
+        $prepared = $this->prepare('UPDATE sondage SET title=?, admin_mail=?, comment=?, active=?, editable=? WHERE poll_id = ?');
 
         return $prepared->execute([$poll->title, $poll->admin_mail, $poll->comment, $poll->active, $poll->editable, $poll->poll_id]);
     }
@@ -86,6 +98,11 @@ class FramaDB {
         return $prepared->fetchAll();
     }
 
+    function insertDefaultVote($poll_id, $insert_position) {
+        $prepared = $this->prepare('UPDATE user_studs SET reponses = CONCAT(SUBSTRING(reponses, 1, ?), "0", SUBSTRING(reponses, ?)) WHERE id_sondage = ?');
+        return $prepared->execute([$insert_position, $insert_position + 1, $poll_id]);
+    }
+
     function insertVote($poll_id, $name, $choices) {
         $prepared = $this->prepare('INSERT INTO user_studs (id_sondage,nom,reponses) VALUES (?,?,?)');
         $prepared->execute([$poll_id, $name, $choices]);
diff --git a/app/classes/Framadate/Services/AdminPollService.php b/app/classes/Framadate/Services/AdminPollService.php
index b6bca393..ce4deb6d 100644
--- a/app/classes/Framadate/Services/AdminPollService.php
+++ b/app/classes/Framadate/Services/AdminPollService.php
@@ -1,8 +1,11 @@
 <?php
 namespace Framadate\Services;
 
+use Framadate\Utils;
+
 /**
  * Class AdminPollService
+ *
  * @package Framadate\Services
  */
 class AdminPollService {
@@ -106,30 +109,111 @@ class AdminPollService {
         $this->connect->commit();
     }
 
-    public function addSlot($poll_id, $newdate, $newmoment) {
-        $ex = explode('/', $newdate);
-        $datetime = mktime(0,0,0, $ex[1], $ex[0], $ex[2]);
+    /**
+     * Add a new slot to the poll. And insert default values for user's votes.
+     * <ul>
+     *  <li>Create a new slot if no one exists for the given date</li>
+     *  <li>Create a new moment if a slot already exists for the given date</li>
+     * </ul>
+     *
+     * @param $poll_id int The ID of the poll
+     * @param $new_date string The date (format: d/m/Y)
+     * @param $new_moment string The moment's name
+     * @return bool true if added
+     */
+    public function addSlot($poll_id, $new_date, $new_moment) {
+        $ex = explode('/', $new_date);
+        $datetime = mktime(0, 0, 0, $ex[1], $ex[0], $ex[2]);
 
-        $slot = $this->connect->findSlotByPollIdAndDatetime($poll_id, $datetime);
+        $slots = $this->connect->allSlotsByPollId($poll_id);
+        $result = $this->findInsertPosition($slots, $datetime, $new_moment);
 
-        if ($slot != null) {
-            // Update found slot
-            $moments = explode('@', $slot->sujet)[1];
-            foreach ($moments as $moment) {
-                if ($moment == $newmoment) {
-                    return false;
-                }
+        // Begin transaction
+        $this->connect->beginTransaction();
+
+        if ($result == null) {
+            // The moment already exists
+            return false;
+        } elseif ($result->slot != null) {
+            $slot = $result->slot;
+
+            $joined_moments = explode('@', $slot->sujet)[1];
+            $moments = explode(',', $joined_moments);
+
+            // Check if moment already exists (maybe not necessary)
+            if (in_array($new_moment, $moments)) {
+                return false;
             }
-            // TODO Implements
+
+            // Update found slot
+            $moments[] = $new_moment;
+            sort($moments);
+            $this->connect->updateSlot($poll_id, $datetime, $datetime . '@' . implode(',', $moments));
 
         } else {
-            // TODO Found index of insertion, in order to update user votes
-            $this->connect->insertSlot($poll_id, $datetime . '@' . $newmoment);
+            $this->connect->insertSlot($poll_id, $datetime . '@' . $new_moment);
         }
 
+        $this->connect->insertDefaultVote($poll_id, $result->insert);
+
+        // Commit transaction
+        $this->connect->commit();
+
         return true;
 
     }
 
+    /**
+     * This method find where to insert a datatime+moment into a list of slots.<br/>
+     * Return the {insert:X}, where X is the index of the moment into the whole poll (ex: X=0 => Insert to the first column).
+     * Return {slot:Y}, where Y is not null if there is a slot existing for the given datetime.
+     *
+     * @param $slots array All the slots of the poll
+     * @param $datetime int The datetime of the new slot
+     * @param $moment string The moment's name
+     * @return null|\stdClass An object like this one: {insert:X, slot:Y} where Y can be null.
+     */
+    private function findInsertPosition($slots, $datetime, $moment) {
+        $result = new \stdClass();
+        $result->slot = null;
+        $result->insert = -1;
+
+        $i = 0;
+
+        foreach ($slots as $slot) {
+            $ex = explode('@', $slot->sujet);
+            $rowDatetime = $ex[0];
+            $moments = explode(',', $ex[1]);
+
+            if ($datetime == $rowDatetime) {
+                $result->slot = $slot;
+
+                foreach ($moments as $rowMoment) {
+                    $strcmp = strcmp($moment, $rowMoment);
+                    if ($strcmp < 0) {
+                        // Here we have to insert at First place or middle of the slot
+                        break(2);
+                    } elseif ($strcmp == 0) {
+                        // Here we dont have to insert at all
+                        return null;
+                    }
+                    $i++;
+                }
+
+                // Here we have to insert at the end of a slot
+                $result->insert = $i;
+                break;
+            } elseif ($datetime < $rowDatetime) {
+                // Here we have to insert a new slot
+                break;
+            } else {
+                $i += count($moments);
+            }
+        }
+        $result->insert = $i;
+
+        return $result;
+    }
+
 }
  
\ No newline at end of file
diff --git a/app/classes/Framadate/Utils.php b/app/classes/Framadate/Utils.php
index cb8a0783..0226eb7c 100644
--- a/app/classes/Framadate/Utils.php
+++ b/app/classes/Framadate/Utils.php
@@ -214,7 +214,7 @@ class Utils
 
     /**
      * This method pretty prints an object to the page framed by pre tags.
-     * @param Object $object The object to print.
+     * @param mixed $object The object to print.
      */
     public static function debug($object)
     {
-- 
GitLab