<?php
/**
 * @copyright © 2007, 2008, 2009 Intrahealth International, Inc.
 * This File is part of I2CE
 *
 * I2CE is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * @package I2CE
 * @author Luke Duncan <lduncan@intrahealth.org>
 * @since v3.0.0
 * @version v3.0.0
 */
if (!class_exists('I2CE_MagicDataStorageMongoDB',false)) {
/**
 * Implement an abstract class.
 */
    require_once "I2CE_MagicDataStorage.php";

/**
 * Configuration class to lookup and save configuration options.
 * @package I2CE 
 * @access public
 */
    class I2CE_MagicDataStorageMongoDB extends I2CE_MagicDataStorage {

        /**
         * @var Mongo The mongo instance.
         */
        protected $mongo;
        /**
         * @var MongoDB The mongo DB instance.
         */
        protected $mongodb;
        /**
         * @var MongoCollection The mongo db instance collection for this storage.
         */
        protected $collection;
        
        /**
         * Construct the storage object
         * @param $db_name The name of the database to use
         * @param $name The name of the storage
         */
        public function __construct($db_name, $name) {
            parent::__construct($name);
            try {
                $this->mongo = new Mongo( "mongodb://XXX:XXX@localhost/" . $db_name,
                       array( "persist" => $db_name . "_" . $name ) );
                $this->mongodb = $this->mongo->$db_name;
                $this->collection = $this->mongodb->$name;
                $this->collection->ensureIndex( array( "hash" => 1 ) );
            } catch( MongoConnectionException $e ) {
                I2CE::raiseError( "Failed to connect to MongDB" );
                $this->mongo = false;
            }
        }

        /**
         * Returns true if this storage mechanism is ready to be used.  false otherwise.
         */
        public function isAvailable() {
            return class_exists( "Mongo", false ) 
                && $this->mongo instanceof Mongo 
                && $this->mongo->connected;
        }


        
        /**
         * Store the given I2CE_MagicDataNode into MongoDB
         * @param I2CE_MagicDataNode $node
         * @returns boolean.  True on sucess
         */
        public function store( $node ){
            $hash = $this->getHash( $node );
            $save_data= array( 'type' => $node->getType(),
                               'path' => $node->getPath() );
                
            $value = $node->getSaveValue();
            if ( $value !== null ) {
                $save_data['value'] = $value;
            }
            $children = $node->getKeys(null,true);
            if ( count( $children ) > 0 ) {
                $save_data['children'] = $children;
            }
            if ( $node instanceof I2CE_MagicData ) {
                $parent = '';
            } else {
                $name = $node->getName();
                if (is_string($name) && strlen($name) == 0) {
                    I2CE::raiseError("Non-existent name on a non-root magic data node");
                    return false;
                }
                $parentNode = $node->getParent();
                if ($parentNode instanceof I2CE_MagicData) {
                    $parent = '/';
                } else {
                    $parent = $parentNode->getPath(false);
                }
            }
 
            if ( $this->collection->update( array( "hash" => $hash ), 
                        array( '$set' => array( "data" => $save_data, 
                                "parent" => $parent ) ), 
                        array( "upsert" => true, "multiple" => false ) ) !== true ) {
                I2CE_MagicDataNode::raiseError( "Error saving to MongoDB " . $node->getPath() .
                                                " Type: " . $node->getType() .
                                                " Value: " . $value .
                                                " Children: " . implode(',',$children) .
                                                " Message: " . $e->getMessage() );
                return false;
            }
            return true;
            
        }
        /**
         * Retrieve the given I2CE_MagicDataNode value and type.
         * @param I2CE_MagicDataNode $node
         * @return array
         */
        public function retrieve( $node ) {
            $hash = $this->getHash( $node );

            $fetch = $this->collection->findOne( array( "hash" => $hash ) );
            if ( $fetch !== null ) {
                $values = $fetch['data'];
                if ( is_array( $values ) ) {
                    if (!array_key_exists('children',$values)) {
                        $values['children'] = array();
                    }
                    if (!array_key_exists('value',$values)) {
                        $values['value'] = null;
                    }
                    return $values;
                }
            }
            return false;
        }
    
        /**
         * Erases the given I2CE_MagicDataNode from the storage mechanism
         * @param I2CE_MagicDataNode
         */
        public function destroy($node) {
            return $this->collection->remove( array( "hash" => $this->getHash( $node ) ) );
        }
    
        /**
         * Delete the whole MongoDB collection
         * @return boolean
         */
        public function clear() {
            I2CE::raiseError( "Clearing all keys from MongoDB" );
            $result = $this->collection->drop();
            I2CE::raiseError( "Clearing all keys from MongoDB Results: " . print_r( $result, true ) );
            return true;
        }

    }

}
# Local Variables:
# mode: php
# c-default-style: bsd
# indent-tabs-mode: nil
# c-basic-offset: 4
# End:
