<?php
/**
 * Description of JasperResourceDescriptor
 *
 * @author Daniel Wendler
 */
namespace Jasper;


class JasperResourceDescriptor {
    private $name;
    private $wsType;
    private $uriString;
    private $isNew;
    private $label;
    private $description;
    private $creationDate;
    private $propResourceType;
    private $propParentFolder;
    private $propReferenceUri;
    private $propAttachementId;
    private $propIsReference;
    private $propHasData;
    private $propVersion;
    private $propRuAlwaysPropmtControls;
    private $propRuReportRenderingView;
    private $propRuInputcontrolRenderingView;
    private $propRuControlsLayout;
    private $propRuIsMainReport;
    private $propSecurityPermissionMask;
    private $propDatasourceDriverClass;
    private $propDatasourceUsername;
    private $propDataSourcePassword;
    private $propDatasourceConnectionUrl;

    private $childResources = array();


    public function __construct($uriString = null) {
        $tmp = explode('/', JasperHelper::url('/' . $uriString));
        $name = $tmp[(sizeof($tmp) - 1)];
        unset($tmp[(sizeof($tmp) - 1)]);
        $parent = JasperHelper::url(implode('/', $tmp));

        // Some default properties for all resourceDescriptors
        $this->setName($name)
             ->setLabel($name)
             ->setDescription($name . ' generated by Jasper.php through REST ' . date('r'))
             ->setIsNew('true')
             ->setPropParentFolder($parent)
             ->setUriString(JasperHelper::url($parent . '/' . $name))
             ->setPropIsReference('false');
    }


    public function buildXml() {
        $xml = new JasperSimpleXml("<resourceDescriptor></resourceDescriptor>");
        if (!empty($this->name)) {
            $xml->addAttribute('name', $this->name);
        }
        if (!empty($this->uriString)) {
            $xml->addAttribute('uriString', $this->uriString);
        }
        if (!empty($this->isNew)) {
            $xml->addAttribute('isNew', $this->isNew);
        }
        if (!empty($this->wsType)) {
            $xml->addAttribute('wsType', $this->wsType);
        }

        $xml->addChild('label')->addCData($this->label);
        $xml->addChild('description')->addCData($this->description);

        if (!empty($this->propParentFolder)) {
            $propParentFolder = $xml->addChild('resourceProperty');
            $propParentFolder->addAttribute('name', 'PROP_PARENT_FOLDER');
            $propParentFolder->addChild('value')->addCData($this->propParentFolder);
        }
        
        if (!empty($this->propAttachementId)) {
            $propAttachementId = $xml->addChild('resourceProperty');
            $propAttachementId->addAttribute('name', 'PROP_ATTACHEMENT_ID');
            $propAttachementId->addChild('value')->addCData($this->propAttachementId);
        }
        
        if (!empty($this->propHasData)) {
            $propHasData = $xml->addChild('resourceProperty');
            $propHasData->addAttribute('name', 'PROP_HAS_DATA');
            $propHasData->addChild('value')->addCData($this->propHasData);
        }
        
        if (!empty($this->propIsReference)) {
            $propIsReference = $xml->addChild('resourceProperty');
            $propIsReference->addAttribute('name', 'PROP_IS_REFERENCE');
            $propIsReference->addChild('value')->addCData($this->propIsReference);
        }
        
        if (!empty($this->propReferenceUri)) {
            $propReferenceUri = $xml->addChild('resourceProperty');
            $propReferenceUri->addAttribute('name', 'PROP_REFERENCE_URI');
            $propReferenceUri->addChild('value')->addCData($this->propReferenceUri);
        }
        
        if (!empty($this->propResourceType)) {
            $propResourceType = $xml->addChild('resourceProperty');
            $propResourceType->addAttribute('name', 'PROP_RESOURCE_TYPE');
            $propResourceType->addChild('value')->addCData($this->propResourceType);
        }
        
        if (!empty($this->propRuAlwaysPropmtControls)) {
            $propRuAlwaysPropmtControls = $xml->addChild('resourceProperty');
            $propRuAlwaysPropmtControls->addAttribute('name', 'PROP_RU_ALWAYS_PROPMT_CONTROLS');
            $propRuAlwaysPropmtControls->addChild('value')->addCData($this->propRuAlwaysPropmtControls);
        }

        if (!empty($this->propRuReportRenderingView)) {
            $propRuReportRenderingView = $xml->addChild('resourceProperty');
            $propRuReportRenderingView->addAttribute('name', 'PROP_RU_REPORT_RENDERING_VIEW');
            $propRuReportRenderingView->addChild('value')->addCData($this->propRuReportRenderingView);
        }

        if (!empty($this->propRuInputcontrolRenderingView)) {
            $propRuInputcontrolRenderingView = $xml->addChild('resourceProperty');
            $propRuInputcontrolRenderingView->addAttribute('name', 'PROP_RU_INPUTCONTROL_RENDERING_VIEW');
            $propRuInputcontrolRenderingView->addChild('value')->addCData($this->propRuInputcontrolRenderingView);
        }

        if (!empty($this->propRuControlsLayout)) {
            $propRuControlsLayout = $xml->addChild('resourceProperty');
            $propRuControlsLayout->addAttribute('name', 'PROP_RU_CONTROLS_LAYOUT');
            $propRuControlsLayout->addChild('value')->addCData($this->propRuControlsLayout);
        }
        
        if (!empty($this->propVersion)) {
            $propVersion = $xml->addChild('resourceProperty');
            $propVersion->addAttribute('name', 'PROP_VERSION');
            $propVersion->addChild('value')->addCData($this->propVersion);
        }

        if (!empty($this->propSecurityPermissionMask)) {
            $propSecurityPermissionMask = $xml->addChild('resourceProperty');
            $propSecurityPermissionMask->addAttribute('name', 'PROP_SECURITY_PERMISSION_MASK');
            $propSecurityPermissionMask->addChild('value')->addCData($this->propSecurityPermissionMask);
        }

        if (!empty($this->propRuIsMainReport)) {
            $propRuIsMainReport = $xml->addChild('resourceProperty');
            $propRuIsMainReport->addAttribute('name', 'PROP_RU_IS_MAIN_REPORT');
            $propRuIsMainReport->addChild('value')->addCData($this->propRuIsMainReport);
        }


        if (!empty($this->propDatasourceDriverClass)) {
            $propDatasourceDriverClass = $xml->addChild('resourceProperty');
            $propDatasourceDriverClass->addAttribute('name', 'PROP_DATASOURCE_DRIVER_CLASS');
            $propDatasourceDriverClass->addChild('value')->addCData($this->propDatasourceDriverClass);
        }

        if (!empty($this->propDatasourceUsername)) {
            $propDatasourceUsername = $xml->addChild('resourceProperty');
            $propDatasourceUsername->addAttribute('name', 'PROP_DATASOURCE_USERNAME');
            $propDatasourceUsername->addChild('value')->addCData($this->propDatasourceUsername);
        }

        if (!empty($this->propDatasourcePassword)) {
            $propDatasourcePassword = $xml->addChild('resourceProperty');
            $propDatasourcePassword->addAttribute('name', 'PROP_DATASOURCE_PASSWORD');
            $propDatasourcePassword->addChild('value')->addCData($this->propDatasourcePassword);
        }

        if (!empty($this->propDatasourceConnectionUrl)) {
            $propDatasourceConnectionUrl = $xml->addChild('resourceProperty');
            $propDatasourceConnectionUrl->addAttribute('name', 'PROP_DATASOURCE_CONNECTION_URL');
            $propDatasourceConnectionUrl->addChild('value')->addCData($this->propDatasourceConnectionUrl);
        }

        // A resourceDescriptor can contain child resourceDescriptors
        foreach ($this->childResources as $childResource) {
            $xml->addXmlObject($childResource->buildXml());
        }

        return $xml;
    }


    public function toXml($pretty = false) {
        return $this->buildXml()->saveXml($pretty);
    }


    public function fromXml(\SimpleXMLElement $resource) {
        $this->setName((string)$resource['name'])
                   ->setUriString((string)$resource['uriString'])
                   ->setLabel((string)$resource->label)
                   ->setWsType((string)$resource['wsType'])
                   ->setDescription((string)$resource->description)
                   ->setIsNew((string)$resource['isNew'])
                   ->setCreationDate((string)$resource->creationDate);

        // Calling setter for each resourceProperty
        foreach ($resource->resourceProperty as $property) {
            // PROP_XXX_AAA to propXxxAaa
            $member = lcfirst(implode(array_map('ucfirst', explode('_', strtolower((string)$property['name'])))));
            if (method_exists($this, 'set' . ucfirst($member))) {
                // propXxxAaa to setPropXxxAaa
                call_user_func(array($this, 'set' . ucfirst($member)), (string)$property->value);
            }
        }

        // Creating new child resourceDescriptors
        foreach ($resource->resourceDescriptor as $childResource) {
            $resourceDescriptor = new JasperResourceDescriptor();
            $resourceDescriptor->fromXml($childResource);
            $this->addChildResource($resourceDescriptor);
        }

        return $this;
    }


    public function getChildResources() {
        return $this->childResources;
    }


    public function addChildResource(JasperResourceDescriptor $resource) {
        // Some resources have to be references to themselves,
        // when added as a child resource.
        if ($resource->getWsType() == 'jrxml') {
            $resource->setPropIsReference('true');
            $resource->setPropReferenceUri($resource->getUriString());
        }
        $this->childResources[] = $resource;
        return $this;
    }


    public function removeChildResource(JasperResourceDescriptor $resource) {
        foreach ($this->childResources as $key => $childResource) {
            if ($childResource->getUriString() == $resource->getUriString()) {
                unset($this->childResources[$key]);
            }
        }
        return $this;
    }


    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
        return $this;
    }

    public function getWsType() {
        return $this->wsType;
    }

    public function setWsType($wsType) {
        $this->wsType = $wsType;
        return $this;
    }

    public function getUriString() {
        return $this->uriString;
    }

    public function setUriString($uriString) {
        $tmp = explode('/', JasperHelper::url('/' . $uriString));
        $name = $tmp[(sizeof($tmp) - 1)];
        unset($tmp[(sizeof($tmp) - 1)]);
        $parent = JasperHelper::url(implode('/', $tmp));

        if (empty($this->propParentFolder)) {
            $this->setPropParentFolder($parent);
        }

        if (empty($this->name)) {
            $this->setName($name);
        }

        $this->uriString = $uriString;
        return $this;
    }

    public function getIsNew() {
        return $this->isNew;
    }

    public function setIsNew($isNew) {
        if ($isNew === true) {
            $isNew = 'true';
        }
        if ($isNew === false) {
            $isNew = 'false';
        }
        $this->isNew = $isNew;
        return $this;
    }

    public function getLabel() {
        return $this->label;
    }

    public function setLabel($label) {
        $this->label = $label;
        return $this;
    }

    public function getDescription() {
        return $this->description;
    }

    public function setDescription($description) {
        $this->description = $description;
        return $this;
    }

    public function getPropResourceType() {
        return $this->propResourceType;
    }

    public function setPropResourceType($propResourceType) {
        $this->propResourceType = $propResourceType;
        return $this;
    }

    public function getPropParentFolder() {
        return $this->propParentFolder;
    }

    public function setPropParentFolder($propParentFolder) {
        $this->propParentFolder = $propParentFolder;
        return $this;
    }

    public function getPropReferenceUri() {
        return $this->propReferenceUri;
    }

    public function setPropReferenceUri($propReferenceUri) {
        $this->propReferenceUri = $propReferenceUri;
        return $this;
    }

    public function getPropAttachementId() {
        return $this->propAttachementId;
    }

    public function setPropAttachementId($propAttachementId) {
        $this->propAttachementId = $propAttachementId;
        return $this;
    }

    public function getPropIsReference() {
        return $this->propIsReference;
    }

    public function setPropIsReference($propIsReference) {
        $this->propIsReference = $propIsReference;
        return $this;
    }

    public function getPropHasData() {
        return $this->propHasData;
    }

    public function setPropHasData($propHasData) {
        $this->propHasData = $propHasData;
        return $this;
    }

    public function getPropVersion() {
        return $this->propVersion;
    }

    public function setPropVersion($propVersion) {
        $this->propVersion = $propVersion;
        return $this;
    }

    public function getPropRuAlwaysPropmtControls() {
        return $this->propRuAlwaysPropmtControls;
    }

    public function setPropRuAlwaysPropmtControls($propRuAlwaysPropmtControls) {
        $this->propRuAlwaysPropmtControls = $propRuAlwaysPropmtControls;
        return $this;
    }

    public function getPropRuControlsLayout() {
        return $this->propRuControlsLayout;
    }

    public function setPropRuControlsLayout($propRuControlsLayout) {
        $this->propRuControlsLayout = $propRuControlsLayout;
        return $this;
    }

    public function getPropSecurityPermissionMask() {
        return $this->propSecurityPermissionMask;
    }
    
    public function setPropSecurityPermissionMask($propSecurityPermissionMask) {
        $this->propSecurityPermissionMask = $propSecurityPermissionMask;
        return $this;
    }

    public function getPropRuReportRenderingView() {
        return $this->propRuReportRenderingView;
    }

    public function setPropRuReportRenderingView($propRuReportRenderingView) {
        $this->propRuReportRenderingView = $propRuReportRenderingView;
        return $this;
    }

    public function getPropRuInputcontrolRenderingView() {
        return $this->propRuInputcontrolRenderingView;
    }

    public function setPropRuInputcontrolRenderingView($propRuInputcontrolRenderingView) {
        $this->propRuInputcontrolRenderingView = $propRuInputcontrolRenderingView;
        return $this;
    }

    public function getPropRuIsMainReport() {
        return $this->propRuIsMainReport;
    }

    public function setPropRuIsMainReport($propRuIsMainReport) {
        $this->propRuIsMainReport = $propRuIsMainReport;
        return $this;
    }

    public function getPropDatasourceDriverClass() {
        return $this->propDatasourceDriverClass;
    }

    public function setPropDatasourceDriverClass($propDatasourceDriverClass) {
        $this->propDatasourceDriverClass = $propDatasourceDriverClass;
        return $this;
    }

    public function getPropDatasourceUsername() {
        return $this->propDatasourceUsername;
    }

    public function setPropDatasourceUsername($propDatasourceUsername) {
        $this->propDatasourceUsername = $propDatasourceUsername;
        return $this;
    }

    public function getPropDataSourcePassword() {
        return $this->propDataSourcePassword;
    }

    public function setPropDataSourcePassword($propDataSourcePassword) {
        $this->propDataSourcePassword = $propDataSourcePassword;
        return $this;
    }

    public function getPropDatasourceConnectionUrl() {
        return $this->propDatasourceConnectionUrl;
    }

    public function setPropDatasourceConnectionUrl($propDatasourceConnectionUrl) {
        $this->propDatasourceConnectionUrl = $propDatasourceConnectionUrl;
        return $this;
    }

    public function getCreationDate() {
        return $this->creationDate;
    }
    
    public function setCreationDate($creationDate) {
        $this->creationDate = $creationDate;
        return $this;
    }

    public function getXml($pretty = false) {
        return $this->toXml($pretty);
    }
}