<?php
class category
{
    const TABLE = 'category';
    const DIRECTORY = 'extend/content/category/';
    
    ////////////////////////////////////////////////////////////////////////////
    // Construct and destruct functions.
    
    ////////////////////////////////////////////////////////////////////////////
    // Overload functions.

    ////////////////////////////////////////////////////////////////////////////
    // Interface functions.
    
    public static function get($id = '')
    {
        $q = db::query()->select(self::TABLE);
        
        if (!$id)
        {
            $q->where('parent_id', null);
        }
        else
        {
            $q->where('id', $id);
        }
        
        return $q->execute()->fetch();
    }
    
    public static function get_by_path(array $path)
    {
        $g = db::query()->select(self::TABLE)
                        ->where('parent_id', null)
                        ->execute()->fetch();
        
        if (!$path)
        {
            return $g;
        }
        
        $parent_id = $g['id'];
        
        foreach ($path as $p)
        {
            $c = db::query()->select(self::TABLE)
                            ->where('path', $p)
                            ->where('parent_id', $parent_id)
                            ->execute()->fetch();
            
            if (!$c)
            {
                return '';
            }
            
            $parent_id = $c['id'];
        }
        
        return $c;
    }
    
    public static function get_child($id = '', $grandchild = false)
    {
        $q = db::query()->select(self::TABLE . ' c1')
                        ->column('c1.id', 'c1.parent_id', 'c1.path', 'c1.name', 'c1.content')
                        ->join('meta m', array('AND', array('=', 'c1.id', (object) array('type' => 'identifier', 'value' => 'm.type_id')), array('=', 'm.type', 'category')), 'left')
                        ->column('m.title meta');
        
        if (!$id)
        {
            $id = db::query()->select(self::TABLE . ' all')
                             ->column('all.id')
                             ->where('all.parent_id', null)
                             ->limit(1);
        }
        
        if ($grandchild)
        {
            $q->join(self::TABLE . ' c2', array('c2.parent_id', 'c1.id'), 'left')
              ->column('c2.id id2', 'c2.parent_id parent_id2', 'c2.path path2', 'c2.name name2')
              ->order('c1.name')
              ->order('c2.name');
        }
        
        return $q->where('c1.parent_id', $id)
                 ->execute();
    }
    
    public static function get_count()
    {
        $q = db::query()->select(self::TABLE)
                        ->column(sql::raw('COUNT(id) as total'));
        $row = $q->execute()->fetch();
        return $row['total'];
    }
    
    public static function get_tree()
    {
        $current = db::query()->select(self::TABLE)
                              ->where('parent_id', null)
                              ->execute()->fetch();
        
        $tree = array();
        
        $child = db::query()->select(self::TABLE)
                            ->where('>', 'left', $current['left'])
                            ->where('<', 'right', $current['right'])
                            //->order('left')
                            ->order('parent_id')
                            ->order('name')
                            ->execute();
        
        foreach ($child as $c)
        {  
            $tree[$c['parent_id']][] = $c;
        }
        
        return $tree;
    }
    
    public static function get_featured($limit = null)
    {
        $q = db::query()->select(self::TABLE . ' c')
                        ->column('c.id', 'c.path', 'c.name', 'c.content')
                        ->join(self::TABLE . '_featured cf', array('c.id', 'cf.category_id'), 'inner')
                        ->order('cf.id', 'desc');
        
        if ($limit !== null)
        {
            $q->limit($limit);
        }
        
        return $q->execute();
    }
    
    public static function get_path($id = '')
    {
        $path = array();
        
        if (!$id)
        {
            return '';
        }
        
        $left = db::query()->select(self::TABLE)
                              ->column('left')
                              ->where('id', $id)
                              ->limit(1);
        
        $right = db::query()->select(self::TABLE)
                            ->column('right')
                            ->where('id', $id)
                            ->limit(1);
        
        $category = db::query()->select(self::TABLE)
                              ->where('!=', 'parent_id', null)
                              ->where('<=', 'left', $left)
                              ->where('>=', 'right', $right)
                              ->order('left')
                              ->execute();
        
        foreach ($category as $c)
        {
            $path[$c['id']] = $c['path'];
        }
        
        return ($path) ? implode('/', $path) . '/' : '';
    }
    
    public static function get_path_array($id = '')
    {
        $path = array();
        
        if (!$id)
        {
            return $path;
        }
        
        $left = db::query()->select(self::TABLE)
                              ->column('left')
                              ->where('id', $id)
                              ->limit(1);
        
        $right = db::query()->select(self::TABLE)
                            ->column('right')
                            ->where('id', $id)
                            ->limit(1);
        
        $category = db::query()->select(self::TABLE)
                              ->where('!=', 'parent_id', null)
                              ->where('<=', 'left', $left)
                              ->where('>=', 'right', $right)
                              ->order('left')
                              ->execute();
        
        foreach ($category as $c)
        {
            $path[$c['id']] = $c['path'];
        }
        
        return $path;
    }
    
    public static function get_image($id)
    {
        $category = self::get($id);
        
        if (!$category) {
            throw new Exception('Category does not exist.');
        }
        
        if ($category['image']) {
            $image = self::DIRECTORY . $category['path'] . '/' . $category['image'];
            
            if (is_file($image)) {
                return $category['image'];
            }
        }
        
        $path = self::DIRECTORY . $category['path'] . '/';
        
        if (is_dir($path)) {
            $files = new DirectoryIterator($path);
            
            foreach ($files as $file) {
                if (!$file->isDot() && !$file->isDir()) {
                    return $file->getFilename();
                }
            }
        }
    }
    
    public static function get_image_list($id)
    {
        $category = self::get($id);
        
        if (!$category) {
            throw new Exception('Category does not exist.');
        }
        
        $images = array();
        $path = self::DIRECTORY . $category['path'] . '/';
        
        if (is_dir($path)) {
            $files = new DirectoryIterator($path);
            
            foreach ($files as $file) {
                if (!$file->isDot() && !$file->isDir()) {
                    $images[] = $file->getFilename();
                }
            }
        }
        
        return $images;
    }
    
    public static function get_image_url($id, $filename, $width, $height)
    {
        $category = self::get($id);
        
        if (!$category) {
            throw new Exception('Category does not exist.');
        }
        
        $directory = self::DIRECTORY . $category['path'] . '/thumbnail/';
        
        if (!is_dir($directory)) {
            folder::create($directory);
            folder::mode($directory, 0755);
        }
        
        $file = self::DIRECTORY . $category['path'] . '/' . $filename;
        
        if (!$file) {
            throw new Exception('Category image does not exist.');
        }
        
        $url = self::DIRECTORY . $category['path'] . '/thumbnail/' . $width . '-' . $height . '-' . $filename;
        
        if (!is_file($url)) {
            $image = new image($file);
            $image->resize($width, $height);
            $image->save($url);
            folder::mode($url, 0755);
        }
        
        return $url;
    }
    
    public static function add(array $data)
    {
        db::get()->begin();
        $parent = db::query()->select(self::TABLE)
                             ->where('id', $data['parent_id'])
                             ->execute()->fetch();
        
        db::query()->update(self::TABLE)
                   ->column('left', sql::raw('`left` + 2'))
                   ->where('>', 'left', $parent['left'])
                   ->execute();
            
        db::query()->update(self::TABLE)
                   ->column('right', sql::raw('`right` + 2'))
                   ->where('>', 'right', $parent['left'])
                   ->execute();
        
        $data['left'] = $parent['left'] + 1;
        $data['right'] = $parent['left'] + 2;
        db::query()->insert(self::TABLE)
                   ->column($data)
                   ->execute();
        
        $id = db::get()->get_last_id();
        db::get()->commit();
        folder::create(self::DIRECTORY . $data['path']);
        folder::mode(self::DIRECTORY . $data['path'], 0755);
        $files = new DirectoryIterator(self::DIRECTORY . 'category/');
        
        foreach ($files as $file) {
            if (!$file->isDot() && !$file->isDir()) {
                folder::move(self::DIRECTORY . 'category/' . $file->getFilename(), self::DIRECTORY . $data['path'] . '/' . $file->getFilename());
                folder::mode(self::DIRECTORY . $data['path'] . '/' . $file->getFilename(), 0755);
            }
        }
        
        unset($data['id'], $data['left'], $data['parent_id'], $data['right']);
        search::save('category', $id, strip_tags(implode(' ', $data)), $data['name']);
        return $id;
    }
    
    public static function edit($id, array $data)
    {
        $category = self::get($id);
        
        if ($category) {
            db::query()->update(self::TABLE)
                       ->column($data)
                       ->where('id', $id)
                       ->limit(1)
                       ->execute();
            
            $current_path = self::DIRECTORY . $category['path'] . '/';
            $new_path = self::DIRECTORY . $data['path'] . '/';
            
            if (!is_dir($current_path)) {
                folder::create($current_path);
                folder::mode($current_path, 0755);
            }
            
            if ($category['path'] !== $data['path']) {
                folder::move($current_path, $new_path);
                $files = new DirectoryIterator($new_path);
                
                foreach ($files as $file) {
                    if (!$file->isDot()) {
                        folder::mode($new_path . $file->getFilename(), 0755);
                    }
                }
            }
            
            unset($data['id'], $data['left'], $data['parent_id'], $data['right']);
            search::save('category', $id, strip_tags(implode(' ', $data)), $data['name']);
        }
    }
    
    public static function delete($id)
    {
        db::get()->begin();
        
        $current = self::get($id);
        
        if (!$current || !$current['parent_id'])
        {
            return;
        }
        
        $product = array();
        $category = array();
        $all = db::query()->select('product p')
                          ->join('category c', array('p.category_id', 'c.id'), 'inner')
                          ->where('>=', 'c.left', $current['left'])
                          ->where('<=', 'c.right', $current['right'])
                          ->execute();
        
        foreach ($all as $p)
        {
            $product[] = $p['id'];
            folder::delete(product::DIRECTORY . $p['path']);
        }
        
        $all = db::query()->select(self::TABLE)
                          ->where('>=', 'left', $current['left'])
                          ->where('<=', 'right', $current['right'])
                          ->execute();
        
        foreach ($all as $c)
        {
            $category[] = $c['id'];
            folder::delete(self::DIRECTORY . $c['path']);
        }
        
        if ($product)
        {
            db::query()->delete('product')
                       ->where('id', $product)
                       ->execute();
            
            db::query()->delete('search')
                       ->where('type', 'product')
                       ->where('type_id', $product)
                       ->execute();
        }
        
        db::query()->delete(self::TABLE)
                   ->where('id', $category)
                   ->execute();
        
        db::query()->delete('search')
                   ->where('type', 'category')
                   ->where('type_id', $category)
                   ->execute();
        
        db::query()->delete(self::TABLE . '_featured')
                   ->where('category_id', $category)
                   ->execute();
        
        db::query()->update(self::TABLE)
                   ->column('left', sql::raw('`left` - ' . (count($category) * 2)))
                   ->where('>', 'left', $current['left'])
                   ->execute();
        
        db::query()->update(self::TABLE)
                   ->column('right', sql::raw('`right` - ' . (count($category) * 2)))
                   ->where('>=', 'right', $current['right'])
                   ->execute();
        
        db::get()->commit();
        
        foreach ($product as $p)
        {
            if (is_dir(product::DIRECTORY . $p['path']))
            {
                folder::delete(product::DIRECTORY . $p['path']);
            }
        }
        
        foreach ($category as $c)
        {
            if (is_dir(self::DIRECTORY . $c['path']))
            {
                folder::delete(self::DIRECTORY . $c['path']);
            }
        }
    }
    
    public static function feature($id)
    {
        self::unfeature($id);
        db::query()->insert(self::TABLE . '_featured')
                   ->column(array('category_id' => $id))
                   ->execute();
    }
    
    public static function is_featured($id)
    {
        return (boolean) count(db::query()->select(self::TABLE . '_featured')
                                          ->where('category_id', $id)
                                          ->limit(1)
                                          ->execute());
    }
    
    public static function unfeature($id)
    {
        db::query()->delete(self::TABLE . '_featured')
                   ->where('category_id', $id)
                   ->execute();
    }
    
    public static function get_views($id = null)
    {
        $q = db::query()->select(self::TABLE)
                        ->column(sql::raw('SUM(views) as total'));
        
        if ($id !== null)
        {
            $q->where('id', $id);
        }
        
        $row = $q->execute()->fetch();
        return $row['total'];
    }
    
    public static function save_view($id)
    {
        db::query()->update(self::TABLE)
                   ->column('views', sql::raw('views + 1'))
                   ->where('id', $id)
                   ->execute();
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // Internal functions.
}
