<?php
/**
 * This file is part of the DATAtourisme project.
 *
 *  @author Conjecto <contact@conjecto.com>
 *
 * For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
 */

namespace Datatourisme\Api\Resolver\SparqlResolver\QueryBuilder;

use Datatourisme\Api\Resolver\SparqlResolver\Collection\Collection;
use Datatourisme\Api\Resolver\SparqlResolver\Collection\FlatCollection;
use Datatourisme\Api\Resolver\SparqlResolver\Sparql\Construct;
use Datatourisme\Api\Resolver\SparqlResolver\Sparql\Limit;
use Datatourisme\Api\Resolver\SparqlResolver\Sparql\Offset;
use Datatourisme\Api\Resolver\SparqlResolver\Sparql\OrderBy;
use Datatourisme\Api\Resolver\SparqlResolver\Sparql\Select;
use Datatourisme\Api\Resolver\SparqlResolver\Sparql\Where;

class QueryBuilder
{
    protected $select;
    protected $construct;
    protected $where;
    protected $orderBy;
    protected $limit;
    protected $offset;

    public function __construct()
    {
        $this->select = new Collection();
        $this->construct = new FlatCollection();
        $this->where = new FlatCollection();
        $this->orderBy = new Collection();
        $this->limit = null;
        $this->offset = null;
    }

    public function select($select)
    {
        if ($this->construct->count() > 0) {
            throw new \Exception('construct already exists');
        }
        $this->addSelect($select);

        return $this;
    }

    public function addSelect($select)
    {
        if ($this->construct->count() > 0) {
            throw new \Exception('construct already exists');
        }
        $this->select->append($select);

        return $this;
    }

    public function construct($construct)
    {
        if ($this->select->count() > 0) {
            throw new \Exception('select already exists');
        }
        $this->addConstruct($construct);

        return $this;
    }

    public function addConstruct($construct)
    {
        if ($this->select->count() > 0) {
            throw new \Exception('select already exists');
        }
        $this->construct->append($construct);

        return $this;
    }

    public function where($where)
    {
        $this->addWhere($where);

        return $this;
    }

    public function addWhere($where)
    {
        $this->where->append($where);

        return $this;
    }

    public function orderBy($orderBy)
    {
        $this->orderBy = $orderBy;

        return $this;
    }

    public function limit($limit)
    {
        $this->limit = $limit;

        return $this;
    }

    public function offset($offset)
    {
        $this->offset = $offset;

        return $this;
    }

    public function getQuery()
    {
        $query = new Collection();
        if (0 == $this->construct->count() && 0 == $this->select->count()) {
            throw new \Exception('No select or construct defined');
        }
        if ($this->construct->count()) {
            $query->add(new Construct($this->construct));
        } elseif ($this->select->count()) {
            $query->add(new Select($this->select));
        }
        if (0 == $this->where->count()) {
            throw new \Exception("Where can't be empty");
        }
        $query->add(new Where($this->where));
        if ($this->orderBy->count()) {
            $query->add(new OrderBy($this->orderBy));
        }

        if (null !== $this->limit) {
            $query->add(new Limit($this->limit));
        }

        if (null !== $this->offset) {
            $query->add(new Offset($this->offset));
        }

        return (string) $query;
    }

    public function __toString()
    {
        return $this->getQuery();
    }
}
