<?php
/**
 * Database CREATE TABLE query
 *
 * This file is part of Zoph.
 *
 * Zoph is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Zoph is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Zoph; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * @package Zoph
 * @author Jeroen Roos
 */

namespace db;

/**
 * Database CREATE TABLE query
 *
 * @package Zoph
 * @author Jeroen Roos
 */
class create extends query {

    /** @var string name of the table */
    private $name;

    /** @var string MariaDB engine */
    private $engine="InnoDB";

    /** @var array columns */
    private $columns=array();

    /** @var array primary keys */
    private $pKeys=array();

    /** @var array keys */
    private $keys=array();

    /** @var array index */
    private $index=array();

    /** @var array keylength */
    private $keyLength=array();

    /** @var array columns that can not be 'null'  */
    private $notNull=array();

    /** @var bool create table with IF NOT EXISTS statement  */
    private $ifNotExists=false;

    /**
     * Create a new table
     * @param string name
     * @param array columns
     */
    public function __construct(string $name) {
        $this->name=$name;
    }

    public function addColumns(array $columns) : void {
        foreach ($columns as $column) {
            $this->addColumn($column);
        }
    }

    public function addColumn(column $column) : void {
        $this->columns[]=$column;
    }

    public function addIndex(string $name, array $fields) : void {
        $this->index[$name]=$fields;
    }

    public function ifNotExists($if = true) : void {
        $this->ifNotExists = $if;
    }

    /**
     * Build the clause
     * @return string clause
     */
    public function __toString() : string {
        $this->pKeys=array();
        $this->keys=array();
        $this->notNull=array();

        $sql = "CREATE TABLE " . ($this->ifNotExists ? "IF NOT EXISTS " : "") .
            db::getPrefix() . $this->name . " (\n";
        foreach ($this->columns as $column) {
            $sql .= "  " . $column . ",\n";
            if ($column->isKey()) {
                $this->keys[$column->getKeyName()]=$column;
                $this->keyLength[$column->getKeyName()]=$column->getKeyLength();
            }
            if ($column->isPrimaryKey()) {
                $this->pKeys[]=$column->getName();
            }
            if ($column->isNotNull()) {
                $this->notNull[]=$column;
            }
        }

        $sql .= $this->getKeyString();
        $sql .= $this->getIndexString();

        // Remove last comma
        $sql = substr($sql, 0, -2) . "\n";
        $sql .= ") ENGINE=" . $this->engine;
        return $sql;
    }

    /**
     * Get KEY and PRIMARY KEY statements
     * @return string SQL snippet.
     */
    private function getKeyString() : string {
        $sql = "";

        if (!empty($this->pKeys)) {
            $sql .= "  PRIMARY KEY (" . implode(", ", $this->pKeys) . "),\n";
        }

        if (!empty($this->keys)) {
            foreach ($this->keys as $name => $column) {
                if ($this->keyLength[$name] > 0) {
                    $length = "(" . $this->keyLength[$name] . ")";
                } else {
                    $length = "";
                }
                $sql .= "  KEY " . $name . "(" . $column->getName() . $length . "),\n";
            }

        }

        return $sql;
    }

    /**
     * Get INDEX statements
     * INDEX and KEY are synonyms in MySQL, we use KEY for single column indices and
     * INDEX for multi-column indices except for PRIMARY KEYs.
     * @return string SQL snippet
     */
    private function getIndexString() : string {
        $sql = "";
        if (!empty($this->index)) {
            foreach ($this->index as $name => $columns) {
                $sql .= "  INDEX " . $name . " (" . implode(", ", $columns) . "),\n";
            }
        }
        return $sql;
    }

}
