<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */
namespace dosamigos\semantic\collections;

use dosamigos\semantic\DosAmigosAsset;
use dosamigos\semantic\helpers\Ui;
use dosamigos\semantic\helpers\Element;
use dosamigos\semantic\Widget;
use yii\helpers\ArrayHelper;

/**
 * Message renders a Semantic UI message
 *
 * @see http://semantic-ui.com/collections/message.html
 *
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\collections
 */
class Message extends Widget
{
    /**
     * @var string the icon to render with the message box. Semantic-ui provides a style for rendering icons. Check
     * [the documentation](http://semantic-ui.com/collections/message.html) for further references.
     *
     * Note: This attribute expects the full HTML of the icon. See [[Ui::icon]].
     */
    public $icon;
    /**
     * @var array the options for rendering the header tag.
     * The header tag is displayed within the content tag and is specified here to ease the task. If false or empty, it
     * won't be rendered.
     *
     * The following special options are supported:
     *
     * - label: string, the header text.
     * - options: array, the HTML attributes of the header.
     *
     */
    public $header = [];
    /**
     * @var string the body content in the alert component. Note that anything between
     * the [[begin()]] and [[end()]] calls of the Alert widget will also be treated
     * as the body content, and will be rendered before this.
     */
    public $body;
    /**
     * @var array the HTML options for rendering the close icon.
     * The close button is displayed in the header of the modal window. Clicking
     * on the button will hide the modal window. If this is false, no close button will be rendered.
     */
    public $closeIcon = [];

    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        $this->initOptions();

        echo Ui::beginTag('div', $this->options) . "\n";
        echo $this->renderBodyBegin() . "\n";
    }

    /**
     * @inheritdoc
     */
    public function run()
    {
        echo "\n" . $this->renderBodyEnd();
        echo "\n" . Ui::endTag('div');

        $this->registerClientScript();
    }

    /**
     * Renders the close button and its header (if any)
     *
     * @return string the begin of the body
     */
    public function renderBodyBegin()
    {
        $lines[] = $this->renderCloseButton();
        if ($this->icon !== null) {
            $lines[] = $this->icon;
        }
        $lines[] = $this->renderHeader();

        return implode("\n", $lines);
    }

    /**
     * Renders the body (if any) and the final closing tags of the message
     * @return string the end of the message's body
     */
    public function renderBodyEnd()
    {
        $lines[] = $this->body;
        if ($this->header !== false || !empty($this->header)) {
            $lines[] = Ui::endTag('div');
        }
        return implode("\n", $lines);
    }

    /**
     * Initializes the message closing buttons
     */
    public function registerClientScript()
    {
        if ($this->closeIcon !== false) {
            $view = $this->getView();
            DosAmigosAsset::register($view);
            $view->registerJs("dosamigos.semantic.initMessageCloseButtons();");
        }
    }

    /**
     * Renders the close button
     *
     * @return string the rendering result
     */
    public function renderCloseButton()
    {
        return $this->closeIcon !== false ? Element::icon('close') : null;
    }

    /**
     * Renders the icon of the message box (if any)
     *
     * @return string the icon
     */
    public function renderIcon()
    {
        return $this->icon;
    }

    /**
     * Renders the header (if any)
     *
     * @return null|string
     */
    public function renderHeader()
    {
        if ($this->header !== false || !empty($this->header)) {
            $content = ArrayHelper::getValue($this->header, 'label', '');
            $options = ArrayHelper::getValue($this->header, 'options', ['class' => 'header']);
            $header = Ui::tag('div', $content, $options);
            $lines[] = Ui::beginTag('div', ['class' => 'content']);
            $lines[] = $header;
            return implode("\n", $lines);
        } else {
            return null;
        }
    }

    /**
     * Initializes the widget options
     */
    public function initOptions()
    {
        Ui::addCssClasses($this->options, ['ui', 'message']);
        if (!empty($this->header) && isset($this->header['options'])) {
            Ui::addCssClass($this->header['options'], 'header');
        }
        if (isset($this->icon)) {
            Ui::addCssClass($this->options, 'icon');
        }
    }

}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use yii\helpers\Html;

/**
 * Radio generates a radio box semantic ui form element
 *
 * @see http://semantic-ui.com/collections/form.html#radio-box
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Radio extends Checkbox
{
    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        Html::addCssClass($this->wrapperOptions, 'radio');
    }

    /**
     * Generates the Radio input
     *
     * @return string the generated radio input tag
     */
    protected function renderInput()
    {
        return $this->hasModel()
            ? Html::activeRadio($this->model, $this->attribute, $this->options)
            : Html::radio($this->name, $this->checked, $this->options);
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\helpers;

use Yii;
use yii\helpers\ArrayHelper;

/**
 * Element provides a set of static methods for generating semantic ui elements HTML tags
 *
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\helpers
 */
class Element
{

    /**
     * Generates a button tag. Differs from [[Ui::button]] on that it allows the creation of a button with different
     * tags
     *
     * @param string $content
     * @param array $options
     *
     * @return string the generated button
     */
    public static function button($content = 'Button', $options = [])
    {
        $tag = ArrayHelper::remove($options, 'tag', 'div');
        Ui::addCssClasses($options, ['ui', 'button']);
        return strcasecmp($tag, 'button') === 0
            ? Ui::button($content, $options)
            : Ui::tag($tag, $content, $options);
    }

    /**
     * Generates an [icon button](http://semantic-ui.com/elements/button.html#icon)
     *
     * @param string $glyph the glyphicon name to be used -ie "cloud"
     * @param array $options the tag options in terms of name-value pairs. These will be rendered as
     * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
     *
     * @return string the generated icon button tag
     */
    public static function iconButton($glyph, $options = [])
    {
        $iOptions = ArrayHelper::remove($options, 'icon', []);
        Ui::addCssClasses($options, ['icon']);
        return static::button(static::icon($glyph, $iOptions), $options);
    }

    /**
     * Generates an [animated button](http://semantic-ui.com/elements/button.html#animated)
     *
     * @param string $visible the initial and visible content of the button
     * @param string $hidden the hidden content of the button. It will be displayed when the button is "on hover" state.
     * @param array $options the tag options in terms of name-value pairs.
     *
     * @return string the generated animated button tag
     */
    public static function animatedButton($visible, $hidden, $options = [])
    {
        $hOptions = ArrayHelper::remove($options, 'hidden', []);
        $vOptions = ArrayHelper::remove($options, 'visible', []);
        Ui::addCssClasses($options, ['ui', 'animated', 'button']);
        Ui::addCssClasses($hOptions, ['hidden', 'content']);
        Ui::addCssClasses($vOptions, ['visible', 'content']);
        $lines = [];
        $lines[] = Ui::tag('div', $hidden, $hOptions);
        $lines[] = Ui::tag('div', $visible, $vOptions);

        return Ui::tag('div', implode("\n", $lines), $options);

    }

    /**
     * Generates a [labeled icon button](http://semantic-ui.com/elements/button.html#labeled-icon)
     *
     * @param string $label the label of the button
     * @param string $glyph the glyphicon name to be used -ie "cloud"
     * @param array $options the tag options in terms of name-value pairs.
     *
     * @return string the generated labeled icon button tag
     */
    public static function labeledIconButton($label, $glyph, $options = [])
    {
        $iOptions = ArrayHelper::remove($options, 'icon', []);
        $icon = static::icon($glyph, $iOptions);
        Ui::addCssClasses($options, ['labeled', 'icon']);
        return static::button($icon . $label, $options);
    }

    /**
     * Generates a [button group](http://semantic-ui.com/elements/button.html#buttons)
     *
     * @param array $buttons the array of button options in terms of name-value pairs to render. The following options
     * are specially handled:
     * - label: string, the label of the button. Defaults to 'label'
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated button group tag
     */
    public static function buttonGroup($buttons = [], $options = [])
    {
        Ui::addCssClasses($options, ['ui', 'buttons']);
        $lines = [];
        foreach ($buttons as $button) {
            $label = ArrayHelper::remove($button, 'label', Yii::t('dosamigos/semantic/helpers', 'label'));
            $lines[] = static::button($label, $button);
        }
        return Ui::tag('div', implode("\n", $lines), $options);
    }

    /**
     * Generates a [conditional button](http://semantic-ui.com/elements/button.html#conditionals)
     *
     * @param string $leftLabel the label to appear on the left side
     * @param string $rightLabel the label to appear on the right side
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated conditional button tag
     */
    public static function conditionalButton($leftLabel, $rightLabel, $options = [])
    {
        $lOptions = ArrayHelper::remove($options, 'left', []);
        $rOptions = ArrayHelper::remove($options, 'right', []);
        $oOptions = ArrayHelper::remove($options, 'or', []);

        Ui::addCssClasses($options, ['ui', 'buttons']);
        Ui::addCssClasses($lOptions, ['ui', 'button']);
        Ui::addCssClasses($rOptions, ['ui', 'button']);
        Ui::addCssClass($oOptions, 'or');

        $lines = [];
        $lines[] = static::button($leftLabel, $lOptions);
        $lines[] = Ui::tag('div', '', $oOptions);
        $lines[] = static::button($rightLabel, $rOptions);

        return Ui::tag('div', implode("\n", $lines), $options);
    }

    /**
     * Renders an [icon tag](http://semantic-ui.com/elements/icon.html)
     *
     * @param string $glyph the name of the icon to render -ie "cloud"
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated icon tag
     */
    public static function icon($glyph, $options = [])
    {
        Ui::addCssClasses($options, ['icon', $glyph]);
        return Ui::tag('i', '', $options);
    }

    /**
     * Renders a [divider](http://semantic-ui.com/elements/divider.html)
     *
     * @param string $label the label
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated divider tag
     */
    public static function divider($label, $options = [])
    {
        Ui::addCssClasses($options, ['ui', 'divider']);

        return Ui::tag('div', $label, $options);
    }

    /**
     * Renders a [flag](http://semantic-ui.com/elements/flag.html)
     *
     * @param string $country the flag's country ISO code to render
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated flag tag
     */
    public static function flag($country, $options = [])
    {
        Ui::addCssClasses($options, ['flag', $country]);
        return Ui::tag('i', '', $options);
    }

    /**
     * Renders an [avatar image](http://semantic-ui.com/elements/image.html#avatar)
     *
     * @param string $src the image source
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated avatar tag
     */
    public static function avatar($src, $options = [])
    {
        Ui::addCssClasses($options, ['ui', 'avatar', 'image']);
        return Ui::img($src, $options);
    }

    /**
     * Renders a [label](http://semantic-ui.com/elements/label.html)
     *
     * @param string $content the label content
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated label tag
     */
    public static function label($content, $options = [])
    {
        $tag = ArrayHelper::remove($options, 'tag', 'div');
        Ui::addCssClasses($options, ['ui', 'label']);
        return Ui::tag($tag, $content, $options);
    }

    /**
     * Generates a [label that contains a detail](http://semantic-ui.com/elements/label.html#detail)
     *
     * @param string $content the content of the label
     * @param string $detail the detail of the label
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated label with detail tag
     */
    public static function labelDetail($content, $detail, $options = [])
    {
        $detail = Ui::tag('div', $detail, ['class' => 'detail']);
        return static::label($content . $detail, $options);
    }

    /**
     * Generates a [tag label](http://semantic-ui.com/elements/label.html#tag)
     *
     * @param string $content the content of the tag label
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated tag label HTML tag
     */
    public static function labelTag($content, $options = [])
    {
        Ui::addCssClass($options, 'tag');
        return static::label($content, $options);
    }

    /**
     * Generates a label ribbon
     *
     * @param string $content the content of the ribbon label
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated ribbon label
     */
    public static function labelRibbon($content, $options = [])
    {
        Ui::addCssClass($options, 'ribbon');
        return static::label($content, $options);
    }

    /**
     * Generates a group of labels. Very useful when working with label tags
     *
     * @param array $labels the array of tag options in terms name-value pairs of . They support a special tag:
     * - content: string, will be extracted from the options
     * @param array $options the tag options in terms of name-value pairs of the layer containing the label group
     *
     * @return string the generated label group tag
     */
    public static function labelGroup($labels = [], $options = [])
    {
        Ui::addCssClasses($options, ['ui', 'labels']);
        $lines = [];
        foreach ($labels as $label) {
            $content = ArrayHelper::remove($label, 'content');
            $lines[] = static::label($content, $label);
        }
        return Ui::tag('div', implode("\n", $lines), $options);
    }

    /**
     * Generates a group list @see http://semantic-ui.com/elements/list.html
     *
     * @param array $items the items to render on the group. Each item configuration supports these special options:
     * - icon, string, optional, the item's icon
     * - image, string, optional, the item's image
     * - header, string, optional, the item's header
     * - description, string, option, the description of the item
     * @param array $options the tag options in terms of name-value pairs of the layer containing the list group
     *
     * @return string the generated list
     */
    public static function groupList($items, $options = [])
    {
        Ui::addCssClasses($options, ['ui', 'list']);
        $lines = [];
        foreach ($items as $item) {
            if (is_string($item)) {
                $lines[] = $item;

            } else {
                $icon = ArrayHelper::remove($item, 'icon');
                $image = ArrayHelper::remove($item, 'image');
                $header = ArrayHelper::remove($item, 'header');
                $description = ArrayHelper::remove($item, 'description');
                if ($description) {
                    $description = Ui::tag('div', $description, ['class' => 'description']);
                }

                $content = [];
                $content[] = $icon;
                $content[] = $image;
                if ($header || $description) {
                    $content[] = Ui::tag('div', $header . $description, ['class' => 'content']);
                }
                $lines[] = Ui::tag('div', implode("\n", $content), $item);
            }
        }
        return Ui::tag('div', implode("\n", $lines), $options);
    }

    /**
     * Generates an image reveal element @see http://semantic-ui.com/elements/reveal.html
     *
     * @param string $visibleSrc the image source to be visible when render
     * @param string $hiddenSrc the image source to be hidden when render
     * @param array $options the tag options in terms of name-value pairs.
     *
     * @return string the generated reveal tag
     */
    public static function imgReveal($visibleSrc, $hiddenSrc, $options = [])
    {
        $lines = [];

        $visibleOptions = ArrayHelper::remove($options, 'visible', []);
        Ui::addCssClasses($visibleOptions, ['visible', 'content']);
        $lines[] = Ui::img($visibleSrc, $visibleOptions);

        $hiddenOptions = ArrayHelper::remove($options, 'hidden', []);
        Ui::addCssClasses($hiddenOptions, ['hidden', 'content']);
        $lines[] = Ui::img($hiddenSrc, $hiddenOptions);

        Ui::addCssClasses($options, ['ui', 'reveal']);
        return Ui::tag('div', implode("\n", $lines), $options);
    }

    /**
     * Renders a segment @see http://semantic-ui.com/elements/segment.html
     *
     * @param string $content the content of the segment
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated segment tag
     */
    public static function segment($content, $options = [])
    {
        Ui::addCssClasses($options, ['ui', 'segment']);
        return Ui::tag('div', $content, $options);
    }

    /**
     * Renders a step element item @see http://semantic-ui.com/elements/step.html
     *
     * @param string $content the content of the item
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated step item tag
     */
    public static function step($content, $options = [])
    {
        Ui::addCssClass($options, 'step');
        $tag = ArrayHelper::remove($options, 'tag', 'div');
        return Ui::tag($tag, $content, $options);
    }

    /**
     * Generates step element @see http://semantic-ui.com/elements/step.html
     *
     * @param array $items the configuration of the steps. The configuration options may include:
     * - tag, string, optional, the layer tag. Defaults to 'div'
     * - icon, string, optional, the icon to display on the step
     * - title, string, optional, the title of the step
     * - description, string, optional, the description of the step
     * @param array $options the tag options in terms of name-value pairs
     *
     * @return string the generated step tag
     */
    public static function steps($items, $options = [])
    {
        $steps = array_map(
            function ($item) {
                $icon = ArrayHelper::remove($item, 'icon', '');
                $title = ArrayHelper::remove($item, 'title', '');
                $description = ArrayHelper::remove($item, 'description');

                if (!empty($title)) {
                    $title = Ui::tag('div', $title, ['class' => 'title']);
                }
                if (!empty($description)) {
                    $description = Ui::tag('div', $description, ['class' => 'description']);
                }
                if (!empty($icon)) {
                    $icon = static::icon($icon);
                    $content = Ui::tag('div', $title . $description, ['class' => 'content']);
                } else {
                    $content = $title . $description;
                }
                return static::step($icon . $content, $item);
            },
            $items
        );

        Ui::addCssClasses($options, ['ui', 'steps']);

        return Ui::tag('div', implode("\n", $steps), $options);
    }
}


<?php
/**
 * @link https://github.com/2amigos/yii2-semantic-ui
 * @copyright Copyright (c) 2013-2015 2amigOS! Consulting Group LLC
 * @license http://opensource.org/licenses/BSD-3-Clause
 */
namespace dosamigos\semantic\modules;

use dosamigos\semantic\InputWidget;
use yii\helpers\Html;

/**
 * Search generates a semantic ui search module
 * For example
 *
 * ```php
 *
 * // with local source
 * echo Search::widget([
 *  'name' => 'basic-test',
 *  'inputOptions' => ['placeholder' => 'Animals...'],
 *  'clientOptions' => [
 *      'type' => 'standard',
 *      'source' => [
 *          ['title' => 'Horse', 'description' => 'An Animal'],
 *          ['title' => 'Cow', 'description' => 'Another Animal']
 *      ],
 *      'searchFields' => ['title'],
 *      'searchFullText' => false
 *  ]
 * ]);
 *
 *
 * // with remote source
 * $uri = \yii\helpers\Url::to(['site/search']) . '&q={query}';
 * echo Search::widget([
 *  'name' => 'category-test',
 *  'type' => Search::TYPE_CATEGORY,
 *  'inputOptions' => ['placeholder' => 'Animals...'],
 *  'options' => [
 *      'class' => 'fluid'
 *  ],
 *  'clientOptions' => [
 *      'apiSettings' => [
 *          'action' => 'search',
 *          'url' => $uri
 *      ],
 *      'searchFullText' => false
 *  ]
 * ]);
 * ```
 *
 * @author Antonio Ramirez <amigo.cobos@gmail.com>
 * @link http://www.ramirezcobos.com/
 * @link http://www.2amigos.us/
 * @package dosamigos\semantic\modules
 */
class Search extends InputWidget
{
    const TYPE_STANDARD = 'standard';
    const TYPE_CATEGORY = 'category';

    /**
     * @var array the HTML attributes for the input tag.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $inputOptions = [];
    /**
     * @var bool whether to display the search icon or not.
     */
    public $displayIcon = true;
    /**
     * @var array the HTML attributes for the results dropdown.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $resultsOptions = [];
    /**
     * @var string the type of search. It could be of type 'category' or 'standard'
     */
    public $type = self::TYPE_STANDARD;

    /**
     * @inheritdoc
     * @throws \yii\base\InvalidConfigException
     */
    public function init()
    {
        parent::init();
        Html::addCssClass($this->resultsOptions, 'results');
        Html::addCssClass($this->options, 'search');
        if(!empty($this->type)) {
            Html::addCssClass($this->options, $this->type);
            $this->clientOptions['type'] = $this->type;
        }
    }

    /**
     * @inheritdoc
     */
    public function run()
    {
        $content = $this->renderInput($this->inputOptions, $this->resultsOptions);
        echo Html::tag('div', $content, $this->options);
        $this->registerPlugin('search');
    }

    /**
     * Generates the search input
     *
     * @param array $options the tag options in terms of name-value pairs
     * @param array $resultsOptions the results layer options in terms of name-value pairs
     *
     * @return string the generated search input
     */
    protected function renderInput($options = [], $resultsOptions = [])
    {
        Html::addCssClass($options, 'prompt');

        $lines = [];
        $input = $this->hasModel()
            ? Html::activeTextInput($this->model, $this->attribute, $options)
            : Html::textInput($this->name, $this->value, $options);

        if (!empty($this->displayIcon)) {
            $lines[] = Html::beginTag('div', ['class' => 'ui icon input']);
            $lines[] = $input;
            $lines[] = Html::tag('i', '', ['class' => 'icon search']);
            $lines[] = Html::endTag('div');
        } else {
            $lines[] = $input;
        }
        $lines[] = Html::tag('div', '', $resultsOptions);
        return implode("\n", $lines);
    }
}


<?php
/**
 * @copyright 2012 Anthon Pang
 * @license MIT
 */

namespace VIPSoft\Unzip;

/**
 * Unzip class
 *
 * @author Anthon Pang <apang@softwaredevelopment.ca>
 */
class Unzip
{
    /**
     * @var array
     */
    static $statusStrings = array(
        \ZipArchive::ER_OK => 'No error',
        \ZipArchive::ER_MULTIDISK => 'Multi-disk zip archives not supported',
        \ZipArchive::ER_RENAME => 'Renaming temporary file failed',
        \ZipArchive::ER_CLOSE => 'Closing zip archive failed',
        \ZipArchive::ER_SEEK => 'Seek error',
        \ZipArchive::ER_READ => 'Read error',
        \ZipArchive::ER_WRITE => 'Write error',
        \ZipArchive::ER_CRC => 'CRC error',
        \ZipArchive::ER_ZIPCLOSED => 'Containing zip archive was closed',
        \ZipArchive::ER_NOENT => 'No such file',
        \ZipArchive::ER_EXISTS => 'File already exists',
        \ZipArchive::ER_OPEN => 'Can\'t open file',
        \ZipArchive::ER_TMPOPEN => 'Failure to create temporary file',
        \ZipArchive::ER_ZLIB => 'Zlib error',
        \ZipArchive::ER_MEMORY => 'Malloc failure',
        \ZipArchive::ER_CHANGED => 'Entry has been changed',
        \ZipArchive::ER_COMPNOTSUPP => 'Compression method not supported',
        \ZipArchive::ER_EOF => 'Premature EOF',
        \ZipArchive::ER_INVAL => 'Invalid argument',
        \ZipArchive::ER_NOZIP => 'Not a zip archive',
        \ZipArchive::ER_INTERNAL => 'Internal error',
        \ZipArchive::ER_INCONS => 'Zip archive inconsistent',
        \ZipArchive::ER_REMOVE => 'Can\'t remove file',
        \ZipArchive::ER_DELETED => 'Entry has been deleted',
    );

    /**
     * Make sure target path ends in '/'
     *
     * @param string $path
     *
     * @return string
     */
    private function fixPath($path)
    {
        if (substr($path, -1) === '/') {
            $path .= '/';
        }

        return $path;
    }

    /**
     * Open .zip archive
     *
     * @param string $zipFile
     *
     * @return \ZipArchive
     */
    private function openZipFile($zipFile)
    {
        $zipArchive = new \ZipArchive;

        if ($zipArchive->open($zipFile) !== true) {
            throw new \Exception('Error opening '.$zipFile);
        }

        return $zipArchive;
    }

    /**
     * Extract list of filenames from .zip
     *
     * @param \ZipArchive $zipArchive
     *
     * @return array
     */
    private function extractFilenames(\ZipArchive $zipArchive)
    {
        $filenames = array();
        $fileCount = $zipArchive->numFiles;

        for ($i = 0; $i < $fileCount; $i++) {
            if (($filename = $this->extractFilename($zipArchive, $i)) !== false) {
                $filenames[] = $filename;
            }
        }

        return $filenames;
    }

    /**
     * Test for valid filename path
     *
     * The .zip file is untrusted input.  We check for absolute path (i.e., leading slash),
     * possible directory traversal attack (i.e., '..'), and use of PHP wrappers (i.e., ':').
     *
     * @param string $path
     *
     * @return boolean
     */
    private function isValidPath($path)
    {
        $pathParts = explode('/', $path);

        if (!strncmp($path, '/', 1) ||
            array_search('..', $pathParts) !== false ||
            strpos($path, ':') !== false)
        {
            return false;
        }

        return true;
    }

    /**
     * Extract filename from .zip
     *
     * @param \ZipArchive $zipArchive Zip file
     * @param integer     $fileIndex  File index
     *
     * @return string
     */
    private function extractFilename(\ZipArchive $zipArchive, $fileIndex)
    {
        $entry = $zipArchive->statIndex($fileIndex);

        // convert Windows directory separator to Unix style
        $filename  = str_replace('\\', '/', $entry['name']);

        if ($this->isValidPath($filename)) {
            return $filename;
        }

        throw new \Exception('Invalid filename path in zip archive');
    }

    /**
     * Get error
     *
     * @param integer $status ZipArchive status
     *
     * @return string
     */
    private function getError($status)
    {
        $statusString = isset($this->statusStrings[$status])
            ? $this->statusStrings[$status]
            :'Unknown status';

        return $statusString . '(' . $status . ')';
    }

    /**
     * Extract zip file to target path
     *
     * @param string $zipFile    Path of .zip file
     * @param string $targetPath Extract to this target (destination) path
     *
     * @return mixed Array of filenames corresponding to the extracted files
     *
     * @throw \Exception
     */
    public function extract($zipFile, $targetPath)
    {
        $zipArchive = $this->openZipFile($zipFile);
        $targetPath = $this->fixPath($targetPath);
        $filenames  = $this->extractFilenames($zipArchive);

        if ($zipArchive->extractTo($targetPath, $filenames) === false) {
            throw new \Exception($this->getError($zipArchive->status));
        }

        $zipArchive->close();

        return $filenames;
    }
}


<?php
/**
 * Copyright (c) 2016 - 2018 by Adam Banaszkiewicz
 *
 * @license   MIT License
 * @copyright Copyright (c) 2016 - 2018, Adam Banaszkiewicz
 * @link      https://github.com/requtize/assetter
 */
namespace Requtize\Assetter;

use Requtize\FreshFile\FreshFile;

/**
 * Asseter class. Manage assets (CSS and JS) for website, and it's
 * dependencies by other assets. Allows load full lib by giving a name
 * or append custom library's files.
 *
 * @author Adam Banaszkiewicz https://github.com/requtize
 */
class Assetter
{
    /**
     * @var Requtize\FreshFile\FreshFile
     */
    protected $freshFile;

    /**
     * Stores collection of libraries to load.
     * @var array
     */
    protected $collection = [];

    /**
     * Stores name of default group for library.
     * @var string
     */
    protected $defaultGroup = 'def';

    /**
     * Loaded libraries.
     * @var array
     */
    protected $loaded = [];

    /**
     * Store namespaces, which will be replaces when some asset will be loaded.
     * @var array
     */
    protected $namespaces = [];

    /**
     * Store events listeners.
     * @var array
     */
    protected $eventListeners = [];

    /**
     * List of registered plugins.
     * @var array
     */
    protected $plugins = [];

    /**
     * Constructor.
     * @param FreshFile $freshFile
     */
    public function __construct(FreshFile $freshFile)
    {
        $this->freshFile = $freshFile;
    }

    /**
     * While cloning self, clears loaded libraries.
     * @return void
     */
    public function __clone()
    {
        $this->loaded = [];
    }

    /**
     * Return clone of this object, without loaded libraries in it.
     * @return Cloned self object.
     */
    public function doClone()
    {
        return clone $this;
    }

    /**
     * Returns FreshFile object.
     * @return FreshFile
     */
    public function getFreshFile()
    {
        return $this->freshFile;
    }

    /**
     * Registers plugin and add to list.
     * @param  PluginInterface $plugin PluginInterface object.
     * @return self
     */
    public function registerPlugin(PluginInterface $plugin)
    {
        $plugin->register($this);

        $this->plugins[] = $plugin;

        return $this;
    }

    public function getRegisteredPlugins()
    {
        return $this->plugins;
    }

    /**
     * Attaches callable method/function to given event name.
     * @param  string   $event    Event name.
     * @param  callable $callable Callback that is fired when event is triggered.
     * @return self
     */
    public function listenEvent($event, $callable)
    {
        $this->eventListeners[$event][] = $callable;

        return $this;
    }

    /**
     * Fires event with specified arguments. Arguments were passed
     * as next params of function.
     * @param  string $event Event name to fire.
     * @param  array  $args  Array fo args.
     * @return array  Modified arguments.
     */
    public function fireEvent($event, array $args = [])
    {
        if(isset($this->eventListeners[$event]) === false)
            return $args;

        foreach($this->eventListeners[$event] as $listener)
            call_user_func_array($listener, $args);

        return $args;
    }

    /**
     * Register namespace.
     * @param  string $ns  Namespace name.
     * @param  string $def Namespace path.
     * @return self
     */
    public function registerNamespace($ns, $def)
    {
        list($ns, $def) = $this->fireEvent('namespace.register', [ $ns, $def ]);

        $this->namespaces[$ns] = $def;

        return $this;
    }

    /**
     * Unregister namespace.
     * @param  string $ns namespace name.
     * @return self
     */
    public function unregisterNamespace($ns)
    {
        list($ns) = $this->fireEvent('namespace.unregister', [ $ns ]);

        unset($this->namespaces[$ns]);

        return $this;
    }

    /**
     * Gets current default global group for files that have not
     * defined in collection, or in append() array.
     * @return string
     */
    public function getDefaultGroup()
    {
        return $this->defaultGroup;
    }

    /**
     * Sets default group for files.
     * @param string $defaultGroup
     * @return self
     */
    public function setDefaultGroup($defaultGroup)
    {
        list($defaultGroup) = $this->fireEvent('default-group.set', [ $defaultGroup ]);

        $this->defaultGroup = $defaultGroup;

        return $this;
    }

    /**
     * Returns full collection of registered assets.
     * @return array
     */
    public function getCollection()
    {
        return $this->collection;
    }

    /**
     * Sets collection of assets.
     * @param  array $collection
     * @return self
     */
    public function setCollection(array $collection)
    {
        list($collection) = $this->fireEvent('collection.set', [ $collection ]);

        $this->collection = [];

        foreach($collection as $asset)
        {
            $this->appendToCollection($asset);
        }

        return $this;
    }

    /**
     * Append asset array to collection. before this, apply required
     * indexes if not exists.
     * @param  array $asset $array with asset data.
     * @return self
     */
    public function appendToCollection(array $data)
    {
        list($data) = $this->fireEvent('append-to-collection', [ $data ]);

        $files = [];

        if(isset($data['files']['js']) && is_array($data['files']['js']))
            $files['js'] = $this->resolveFilesList($data['files']['js'], isset($data['revision']) ? $data['revision'] : null);
        if(isset($data['files']['css']) && is_array($data['files']['css']))
            $files['css'] = $this->resolveFilesList($data['files']['css'], isset($data['revision']) ? $data['revision'] : null);

        $this->collection[] = [
            'order'    => isset($data['order']) ? $data['order'] : 0,
            'name'     => isset($data['name'])  ? $data['name']  : uniqid(),
            'files'    => $files,
            'group'    => isset($data['group']) ? $data['group'] : $this->defaultGroup,
            'require'  => isset($data['require']) ? $data['require'] : []
        ];

        return $this;
    }

    /**
     * Loads assets from given name.
     * @param  string $name Name of library/asset.
     * @return self
     */
    public function load($data)
    {
        list($data) = $this->fireEvent('load', [ $data ]);

        if(is_array($data))
        {
            $this->loadFromArray($data);
        }
        else
        {
            $this->loadFromCollection($data);
        }

        return $this;
    }

    /**
     * Loads given asset (by name) from defined collection.
     * @param  string $name Asset name.
     * @return self
     */
    public function loadFromCollection($name)
    {
        if($this->alreadyLoaded($name))
        {
            return $this;
        }

        list($name) = $this->fireEvent('load-from-collection', [ $name ]);

        foreach($this->collection as $item)
        {
            if($item['name'] === $name)
            {
                $this->loadFromArray($item);
            }
        }

        return $this;
    }

    /**
     * Load asset by given array. Apply registered namespaces for all
     * files' paths.
     * @param  array  $item Asset data array.
     * @return self
     */
    public function loadFromArray(array $data)
    {
        list($data) = $this->fireEvent('load-from-array', [ $data ]);

        $files = [];

        if(isset($data['files']['js']) && is_array($data['files']['js']))
            $files['js'] = $this->resolveFilesList($data['files']['js'], isset($data['revision']) ? $data['revision'] : null);
        if(isset($data['files']['css']) && is_array($data['files']['css']))
            $files['css'] = $this->resolveFilesList($data['files']['css'], isset($data['revision']) ? $data['revision'] : null);

        $item = [
            'order'    => isset($data['order']) ? $data['order'] : 0,
            'name'     => isset($data['name']) ? $data['name'] : uniqid(),
            'files'    => $files,
            'group'    => isset($data['group']) ? $data['group'] : $this->defaultGroup,
            'require'  => isset($data['require']) ? $data['require'] : []
        ];

        if(isset($item['files']['js']) && is_array($item['files']['js']))
            $item['files']['js'] = $this->applyNamespaces($item['files']['js']);
        if(isset($item['files']['css']) && is_array($item['files']['css']))
            $item['files']['css'] = $this->applyNamespaces($item['files']['css']);

        $this->loaded[] = $item;

        if(isset($item['require']) && is_array($item['require']))
        {
            foreach($item['require'] as $name)
            {
                $this->loadFromCollection($name);
            }
        }

        return $this;
    }

    /**
     * Clears loaded list.
     * @return self
     */
    public function clearLoaded()
    {
        $this->loaded = [];

        return $this;
    }

    /**
     * Check if given library name was already loaded.
     * @param  string $name Name of library/asset.
     * @return boolean
     */
    public function alreadyLoaded($name)
    {
        foreach($this->loaded as $item)
        {
            if($item['name'] === $name)
            {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns both CSS and JS tags from given group name.
     * If group name is asterisk (*), will return from all loaded groups.
     * @param  string $group Group name.
     * @return string HTML tags as string.
     */
    public function all($group = '*')
    {
        $this->sort();

        $cssList = $this->getLoadedCssList($group);
        $jsList  = $this->getLoadedJsList($group);

        list($cssList, $jsList) = $this->fireEvent('load.all', [ & $cssList, & $jsList ]);

        $cssList = $this->transformListToLinkHtmlNodes($cssList);
        $jsList  = $this->transformListToScriptHtmlNodes($jsList);

        return implode("\n", $cssList)."\n".implode("\n", $jsList);
    }

    /**
     * Returns CSS tags from given group name.
     * If group name is asterisk (*), will return from all loaded groups.
     * @param  string $group Group name.
     * @return string HTML tags as string.
     */
    public function css($group = '*')
    {
        $this->sort();

        $cssList = $this->getLoadedCssList($group);

        list($cssList) = $this->fireEvent('load.css', [ & $cssList ]);

        $cssList = $this->transformListToLinkHtmlNodes($cssList);

        return implode("\n", $cssList);
    }

    /**
     * Returns JS tags from given group name.
     * If group name is asterisk (*), will return from all loaded groups.
     * @param  string $group Group name.
     * @return string HTML tags as string.
     */
    public function js($group = '*')
    {
        $this->sort();

        $jsList = $this->getLoadedJsList($group);

        list($jsList) = $this->fireEvent('load.js', [ & $jsList ]);

        $jsList = $this->transformListToScriptHtmlNodes($jsList);

        return implode("\n", $jsList);
    }

    protected function resolveFilesList(array $files, $revision = null)
    {
        $result = [];

        foreach($files as $key => $val)
        {
            if(is_numeric($key) && is_string($val))
            {
                $result[] = [
                    'file'     => $val,
                    'revision' => $revision
                ];
            }
            elseif(is_numeric($key) && is_array($val))
            {
                $result[] = [
                    'file'     => isset($val['file']) ? $val['file'] : null,
                    'revision' => isset($val['revision']) ? $val['revision'] : $revision
                ];
            }
            elseif(is_string($key) && is_numeric($val))
            {
                $result[] = [
                    'file'     => $key,
                    'revision' => $val
                ];
            }
        }

        return $result;
    }

    protected function applyNamespaces(array $files)
    {
        foreach($files as $key => $file)
        {
            $files[$key] = str_replace(array_keys($this->namespaces), array_values($this->namespaces), $file);
        }

        return $files;
    }

    protected function resolveGroup($group, $type)
    {
        if($group == null)
        {
            return $this->defaultGroup;
        }

        return $group;
    }

    protected function getLoadedCssList($group)
    {
        $group = $this->resolveGroup($group, 'css');

        $result = [];

        foreach($this->loaded as $item)
        {
            if($group != '*')
            {
                if($item['group'] != $group)
                {
                    continue;
                }
            }

            if(isset($item['files']['css']) && is_array($item['files']['css']))
            {
                $result[] = [
                    'files' => $item['files']['css']
                ];
            }
        }

        return $this->arrayUnique($result);
    }

    protected function transformListToLinkHtmlNodes(array $list)
    {
        $result = [];

        list($list) = $this->fireEvent('transform-list-to-html', [ & $list ]);

        foreach($list as $group)
        {
            foreach($group['files'] as $file)
            {
                $result[] = '<link rel="stylesheet" type="text/css" href="'.$file['file'].($file['revision'] ? '?rev='.$file['revision'] : '').'" />';
            }
        }

        return $result;
    }

    protected function getLoadedJsList($group)
    {
        $group = $this->resolveGroup($group, 'js');

        $result = [];

        foreach($this->loaded as $item)
        {
            if($group != '*')
            {
                if($item['group'] != $group)
                {
                    continue;
                }
            }

            if(isset($item['files']['js']) && is_array($item['files']['js']))
            {
                $result[] = [
                    'files' => $item['files']['js']
                ];
            }
        }

        return $this->arrayUnique($result);
    }

    protected function transformListToScriptHtmlNodes(array $list)
    {
        $result = [];

        foreach($list as $group)
        {
            foreach($group['files'] as $file)
            {
                $result[] = '<script src="'.$file['file'].($file['revision'] ? '?rev='.$file['revision'] : '').'"></script>';
            }
        }

        return $result;
    }

    protected function arrayUnique(array $list)
    {
        $filesLoaded = [];

        foreach($list as $gk => $group)
        {
            foreach($group['files'] as $fk => $file)
            {
                if(in_array($file['file'], $filesLoaded))
                {
                    unset($list[$gk]['files'][$fk]);
                    continue;
                }

                $filesLoaded[] = $file['file'];
            }
        }

        return $list;
    }

    protected function sort()
    {
        array_multisort($this->loaded);
    }
}


<?php

/**
 * Copyright 2013 Stéphane Depierrepont (aka Toorop)
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

namespace Ovh\Sms;

use Ovh\Common\Exception\BadConstructorCallException;
use Ovh\Common\Exception\NotImplementedYetByOvhException;
use Ovh\Sms\SmsClient;

class Sms
{

    private $domain = null;
    private static $smsClient = null;

    /**
     * @param $domain
     *
     * @throws \Ovh\Common\Exception\BadConstructorCallException;
     */
    public function __construct($domain)
    {
        if (!$domain)
            throw new BadConstructorCallException('$domain parameter is missing.');
        $this->setDomain($domain);
    }

    /**
     * Return SMS client
     *
     * @return SmsClient
     */
    private static function getClient()
    {
        if (!self::$smsClient instanceof SmsClient){
            self::$smsClient=new SmsClient();
        };
        return self::$smsClient;
    }

    /**
     * Set domain
     *
     * @param string $domain
     */
    public function setDomain($domain)
    {
        $this->domain = $domain;
    }

    /**
     * Get domain
     *
     * @return null | string domain
     */
    public function getDomain()
    {
        return $this->domain;
    }

    ###
    # Mains methods from OVH Rest API
    ##

    /**
     * Get SMS object properties
     *
     * @return object
     */
    public function getProperties()
    {
        return json_decode(self::getClient()->getProperties($this->domain));
    }

    /**
     * @param array $props (avalaibles keys are callBack and templates)
     * @return boolean
     */
    public function setProperties($props)
    {
        return self::getClient()->setProperties($this->domain, $props);
    }

    /**
     * Get numbers blacklisted associated to the SMS account
     *
     * @return object
     */
    public function getBlacklists()
    {
        return json_decode(self::getClient()->getBlackLists($this->domain));
    }

    /**
     * Delete a number from blacklist
     *
     * @param string $number
     * @return bool
     */
    public function deleteBlacklist($number)
    {
        self::getClient()->deleteBlacklist($this->domain, $number);
        return true;
    }

    /**
     * Get SMS sent associated to the SMS account
     * Wrapper on $this->getOutgoings() for backward compatibility
     *
     * @return array
     * @deprecated
     */
    public function getHistories()
    {
        trigger_error('Deprecated method. Use $this->getOutgoings instead.', E_USER_DEPRECATED);
        return $this->getOutgoings();
    }

    /**
     * Get SMS sent associated to the SMS account
     *
     * @return array
     */
    public function getOutgoings()
    {
        return json_decode(self::getClient()->getOutgoings($this->domain));
    }

    /**
     * Get history object properties
     * Wrapper on $this->getOutgoing() for backward compatibility
     *
     * @return array
     * @deprecated
     */
    public function getHistory($id)
    {
        trigger_error('Deprecated method. Use $this->getOutgoing instead.', E_USER_DEPRECATED);
        return $this->getOutgoing($id);
    }

    /**
     * Get outgoing object properties
     *
     * @param int $id
     * @return object
     */
    public function getOutgoing($id)
    {
        return json_decode(self::getClient()->getOutgoing($this->domain, $id));
    }

    /**
     * Delete the sms history given
     * Wrapper on $this->deleteOutgoing() for backward compatibility
     *
     * @return array
     * @deprecated
     */
    public function deleteHistory($id)
    {
        trigger_error('Deprecated method. Use $this->deleteOutgoing instead.', E_USER_DEPRECATED);
        return $this->deleteOutgoing($id);
    }

    /**
     * Delete the sms history given
     *
     * @param $id
     */
    public function deleteOutgoing($id)
    {
        self::getClient()->deleteOutgoing($this->domain, $id);
    }

    /**
     * Get SMS received associated to the SMS account
     *
     * @return array
     */
    public function getIncomings()
    {
        return json_decode(self::getClient()->getIncomings($this->domain));
    }

    /**
     * Get incoming object properties
     *
     * @param int $id
     * @return object
     */
    public function getIncoming($id)
    {
        return json_decode(self::getClient()->getIncoming($this->domain, $id));
    }

    /**
     * Delete the incoming sms given
     *
     * @param $id
     */
    public function deleteIncoming($id)
    {
        self::getClient()->deleteIncoming($this->domain, $id);
    }

    /**
     * Get users associated to the SMS account
     *
     * @return array
     */
    public function getJobs()
    {
        return json_decode(self::getClient()->getJobs($this->domain));
    }

    /**
     * Get job object properties
     *
     * @param int $id
     * @return object
     */
    public function getJob($id)
    {
        return json_decode(self::getClient()->getJob($this->domain, $id));
    }

    /**
     * Create a new job
     *
     * @param array $opt
     * @return object
     * @throws \Ovh\Common\Exception\BadMethodCallException
     * @throws Exception\SmsException
     */
    public function createJob($opt)
    {
        return json_decode(self::getClient()->createJob($this->domain, $opt));
    }

    /**
     * @param int $id : job id
     * @return void
     * @throws \Ovh\Common\Exception\BadMethodCallException
     * @throws Exception\SmsException
     */
    public function deleteJob($id)
    {
        self::getClient()->deleteJob($this->domain, $id);
    }

    /**
     * Helper to send SMS
     *
     * @param string $from => sender
     * @param string $to => receiver
     * @param string $msg => message
     * @return object
     */
    public function send($from, $to, $msg)
    {
        $opt = array(
            'sender' => $from,
            'receivers' => array($to),
            'message' => $msg
        );
        return $this->createJob($opt);
    }

    /**
     * Get SMS offers available
     *
     * @param string $countryDestination country code ISO 3166-2
     * @param string $countryCurrencyPrice country code ISO 3166-2
     * @param integer $quantity
     *
     * @return object
     */

    public function getSeeOffers($countryDestination, $countryCurrencyPrice, $quantity)
    {
        return json_decode(self::getClient()->getSeeOffers($this->domain, $countryDestination, $countryCurrencyPrice, $quantity));
    }

    /**
     * Purchase SMS credits
     *
     * @param int $quantity
     * @return string (json encoded object)
     * @throws \Ovh\Common\Exception\BadMethodCallException
     * @throws Exception\SmsException
     */
    public function purchase($quantity)
    {
        return json_decode(self::getClient()->purchase($this->domain, $quantity));
    }

    /**
     * Get senders allowed associated to the SMS account
     *
     * @return array
     */
    public function getSenders()
    {
        return json_decode(self::getClient()->getSenders($this->domain));
    }

    /**
     * Get sender object properties
     *
     * @param string $sender
     * @return object
     */
    public function getSender($sender)
    {
        return json_decode(self::getClient()->getSender($this->domain, $sender));
    }

    /**
     *  Create a new sender
     *
     * @param array $sender (keys : sender (requiered) => string, relaunch => string, reason => string)
     * @return void
     * @throws \Ovh\Common\Exception\BadMethodCallException
     * @throws Exception\SmsException
     */
    public function createSender($sender)
    {
        self::getClient()->createSender($this->domain, $sender);
    }

    /**
     * @param array $sender
     * @throws \Ovh\Common\Exception\NotImplementedYetByOvhException
     */
    public function updateSender($sender){
        throw new NotImplementedYetByOvhException();
    }

    /**
     * @param string $sender
     * @throws \Ovh\Common\Exception\NotImplementedYetByOvhException
     */
    public function deleteSender($sender){
        throw new NotImplementedYetByOvhException();
    }

    /**
     * Get users associated to the SMS account
     *
     * @return array
     */
    public function getUsers()
    {
        return json_decode(self::getClient()->getUsers($this->domain));
    }

    /**
     * Get user object properties
     *
     * @param string $user
     * @return object
     */
    public function getUser($user)
    {
        return json_decode(self::getClient()->getUser($this->domain, $user));
    }

    /**
     *
     * @param $user
     * @throws \Ovh\Common\Exception\NotImplementedYetByOvhException
     */
    public function addUser($user){
        throw new NotImplementedYetByOvhException();
    }

    /**
     *
     * @param $user
     * @throws \Ovh\Common\Exception\NotImplementedYetByOvhException
     */
    public function updateUser($user){
        throw new NotImplementedYetByOvhException();
    }

    /**
     *
     * @param $user
     * @throws \Ovh\Common\Exception\NotImplementedYetByOvhException
     */
    public function deleteUser($user){
        throw new NotImplementedYetByOvhException();
    }

}


<?php
/**
 * Copyright 2013 Stéphane Depierrepont (aka Toorop)
 *
 * Authors :
 *  - Stéphane Depierrepont (aka Toorop)
 *  - Gillardeau Thibaut (aka Thibautg16)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * 2015-05-22 - Thibautg16 - ajout "new" /cloud : http://www.ovh.com/fr/cloud/
 */

namespace Ovh\Cloud;

use Ovh\Common\Exception\BadConstructorCallException;
use Ovh\Cloud\CloudClient;
use Ovh\Cloud\Pca;

/**
 * Cloud class
 */
class Cloud
{
	private $passport=null;

	private static $CloudClient=null;

    /**
     * Constructor
     *
     * @param $passport
     * @throws \Ovh\Common\Exception\BadConstructorCallException;
     */
    public function __construct($passport)
    {
		if (!$passport ) {
			throw new BadConstructorCallException( '$passport parameter is missing', 1 );
		}
        $this->passport=$passport;
	}

    /**
     * Return Cloud client
     *
     * @return object cloudClient
     */
    private static function getClient()
    {
        if (!self::$CloudClient instanceof CloudClient) {
            self::$CloudClient = new CloudClient();
        }
        return self::$CloudClient;
    }

    /**
     * Get PCA services associated with this cloud passport
     *
     * @return array of services
     */
    public function getPcaServices()
    {
        return json_decode(self::getClient()->getPcaServices($this->passport));
    }

    /**
     * Return PCA instance
     *
     * @param string $pcaName
     * @return object Pca
     */
    public function getPca($pcaName)
    {
        return new Pca($this->passport,$pcaName);
    }

    /***** OVH Cloud *****/
    /**
    * Get Project Properties
    * GET /cloud/project/{serviceName}
    *
    * @return
    */
    public function getProjectProperties(){
        return json_decode(self::getClient()->getProjectProperties($this->passport));
    }

    /**
    * Delete Instances of Project Cloud Public
    * DELETE /cloud/project/{serviceName}/instance/{instanceId}
    *
    * @return null
    */
    public function deleteInstance($idInstance){
        return json_decode(self::getClient()->deleteInstance($this->passport, $idInstance));
    }

    /**
    * POST Reboot Instance
    * POST /cloud/project/{serviceName}/instance/{instanceId}/reboot
    *
    * @return
    */
    public function postInstanceReboot($idInstance, $type){
        return json_decode(self::getClient()->postInstanceReboot($this->passport, $idInstance, $type));
    }

     /**
    * POST Snapshot Instance
    * POST /cloud/project/{serviceName}/instance/{instanceId}/snapshot
    *
    * @return
    */
    public function postInstanceSnapshot($idInstance, $snapshotName){
        return json_decode(self::getClient()->postInstanceSnapshot($this->passport, $idInstance, $snapshotName));
    }

    /**
    * Get Project Balance
    * GET /cloud/project/{serviceName}/balance
    *
    * @return
    */
    public function getProjectBalance(){
        return json_decode(self::getClient()->getProjectBalance($this->passport));
    }

    /**
    * Get Project Quota
    * GET /cloud/project/{serviceName}/quota
    *
    * @return
    */
    public function getProjectQuota(){
        return json_decode(self::getClient()->getProjectQuota($this->passport));
    }

    /**
    * Get Public Cloud Project Instance
    * GET /cloud/project/{serviceName}/instance
    *
    * @return array of Public Cloud Project Instance
    */
    public function getProjectInstance(){
        return json_decode(self::getClient()->getProjectInstance($this->passport));
    }
}