<?php

include_once($ariadne."/stores/pgsqlstore.phtml");

class pgsqlstore_install extends pgsqlstore {

  function initialize() {
    echo "initializing PostgreSQL store.\n";
    echo "creating nodes table.\n";
    $query_string="
CREATE TABLE nodes (
  path varchar(127) PRIMARY KEY,
  parent varchar(127) NOT NULL,
  object int(11) NOT NULL
);
CREATE INDEX nodes_object on nodes (object);
CREATE INDEX nodes_parent on nodes (parent);
";
    $result=pg_exec($this->connect_id, $query_string);
    if ($result===false) {
      $this->error="ERROR: PostgreSQL: ".pg_errormessage($this->connect_id);
      error($this->error);
    }
    echo "creating objects table.\n";
    $query_string="
CREATE TABLE objects (
  id SERIAL PRIMARY KEY,
  type varchar(16) NOT NULL,
  object text,
  vtype varchar(16) NOT NULL,
  lastchanged TIMESTAMP
);
CREATE INDEX objects_lastchanged on objects(lastchanged);
";
    $result=pg_exec($this->connect_id, $query_string);
    if ($result===false) {
      $this->error="ERROR: PostgreSQL: ".pg_errormessage($this->connect_id);
      error($this->error);
    }

    echo "creating properties table.\n";
    $query_string="
CREATE TABLE properties (
  name varchar(21) PRIMARY KEY
)";
    $result=pg_exec($this->connect_id, $query_string);
    if ($result===false) {
      $this->error="ERROR: PostgreSQL: ".pg_errormessage($this->connect_id);
      error($this->error);
    }

    echo "creating seq_id table.\n";
    $query_string="
CREATE TABLE seq_id (
  path varchar(127) PRIMARY KEY,
  next_id int(11) NOT NULL
)";
    $result=pg_exec($this->connect_id, $query_string);
    if ($result===false) {
      $this->error="ERROR: PostgreSQL: ".pg_errormessage($this->connect_id);
      error($this->error);
    }

    echo "creating types table.\n";
    $query_string="
CREATE TABLE types (
  type varchar(16) NOT NULL,
  implements varchar(16) NOT NULL
);
CREATE INDEX types_type on types(type);
CREATE INDEX types_implements on types(implements);
";
    $result=pg_exec($this->connect_id, $query_string);
    if ($result===false) {
      $this->error="ERROR: PostgreSQL: ".pg_errormessage($this->connect_id);
      error($this->error);
    }

    echo "creating default types.\n";
    $this->add_type("pobject","pobject");
    $this->add_type("pdir","pobject");
    $this->add_type("pdir","pdir");

    echo "creating root dir.\n";
    $query_string="INSERT INTO nodes (path, parent, object) VALUES ('/','..',1)";
    $result=pg_exec($this->connect_id, $query_string);
    if ($result===false) {
      $this->error="ERROR: PostgreSQL: ".pg_errormessage($this->connect_id);
      error($this->error);
    }

    $query_string="INSERT INTO objects (id, type, object, vtype) VALUES (0,'pdir','O:6:\"object\":2:{s:2:\"en\";O:6:\"object\":1:{s:4:\"name\";s:7:\"Ariadne\";}s:3:\"nls\";O:6:\"object\":1:{s:7:\"default\";s:2:\"en\";}}','pdir')";
    $result=pg_exec($this->connect_id, $query_string);
    if ($result===false) {
      $this->error="ERROR: PostgreSQL: ".pg_errormessage($this->connect_id);
      error($this->error);
    }

    // initialize locking tables
    $this->mod_lock->init();

    echo "PostgreSQL store initialized.\n\n";
  }

  function create_property($property, $definition, $indexes="") {
  /**********************************************************************

    This function creates a new property type. This property can then be
  used by objects to set special information on which to quickly search
  using find.

  $name must be a string of at most 16 characters from the set [a-zA-Z0-9_] 
  or '-', starting with a letter (a-zA-Z).

  $definition describes which name value pairs this property contains and
  which type (and size) each value is.
  $definition is defined as: $definition[{name}][{type}]={size}
    {name} is defined like $name above
    (type} can be 'number', 'string' or 'boolean'
    {size} is only used for the string type and can not be more than 255. 
  $indexes describes which indexes the storage layer should consider
    for the property. Default behaviour is to create one index for the
    complete set of name-value pairs. If you want you can create a smaller
    index, or more than one index.
  $indexes is defined as: $indexes[][]={name} || $indexes="none"
    e.g. $indexes[0][0]="name1";
	 $indexes[1][0]="name2"
         $indexes[1][1]="name3";
    this would create two indexes, one on "name1" and one on "name2" and
    "name3".
    {name} is defined like $name above. 
  if $indexes is set to "none", no user indexes will be created on this 
  property. This is usually not a good thing to do. 
   
  **********************************************************************/
    $result=1;
    $this->error="";
    if (eregi("^[a-z][a-z0-9_-]*$",$property) && strlen($property)<=16) {
      $tablename="prop_".AddSlashes($property);
      $create_string="create table prop_$tablename (\n";
      while (list($name, $typedef)=each($definition)) {
        if (!eregi("^[a-z][a-z0-9_-]*$",$name) || strlen($name)>16) {
          $result=0;
          $this->error="Wrong format for type: $name";
          break;
        }   
        $create_string.= "  AR_".$name."  ";
        $indexstring.="AR_$name,";
        while (list($type,$size)=each($typedef)) {
          switch($type) {
	  	  case "string": 
        	                if ($size>0 && $size<256) {
    				  $create_string.="varchar(".$size.") not null,\n";
				} else {
				  $result=0;
				  $this->error="Wrong format for typedefinition $name: incorrect size."; 
				}
  				break;
  		  case "number":
  				$create_string.="int not null,\n";
  				break;
  		  case "boolean":
  				$create_string.="bool not null,\n";
  				break;
          }
        }
      }
      if ($result) {
        // now add the 'object' field.
        $create_string.="object int not null);\n";
        // now add the correct indexes.
        if ($indexes=="none") {
          $indexstring="";
        } else {
          if ($indexes && is_array($indexes)) {
            $indexstring="";
            while ((list($key, $values)=each($indexes)) && $result) {
              $indexstring.="create index ".$tablename."_id".$key.
                            " on ".$tablename."(";
              $comma="";
              while (list($key2, $name)=each($values)) {
                if (eregi("^[a-z][a-z0-9_-]*$",$name) && strlen($name)<=16) {
                  $indexstring.=$comma."AR_".$name;
                } else {
                  $result=0;
                  $this->error="Wrong format for index ".$key." in: ".$name;
                  break;
                }
                $comma=",";
              }
              $indexstring.=");\n";
            }
          } else {
            $indexstring="create index ".$table_name."_id0 on $tablename(".substr($indexstring,0,-1).");\n";    
          }
        }
        if ($result) {
          // add the indexes to the create_string
          $create_string.=$indexstring;
          // finally add the index on the object field and close the query.
          $create_string.="CREATE INDEX ".$tablename."_object on $tablename(object);\n";
          $temp=pg_exec($this->connect_id, $create_string);
          if ($temp) {
		$query_string="insert into properties values ( '".AddSlashes($property)."' )";
          	$temp=pg_exec($this->connect_id, $query_string);
          	if ($temp===false) {
            		$this->error=pg_errormessage($this->connect_id);
            		error("ERROR: PostgreSQL: ".$this->error);
          	}
          } else {
		$this->error=pg_errormessage($this->connect_id);
		error("ERROR: PostgreSQL: ".$this->error);
          }
        }
      }
    } else {
      $result=0;
      $this->error="Wrong format for property name: $property";
    }
    debug("create_property: $create_string");
    return $result;
  }

  function remove_property($property) {
  /**********************************************************************

    This function removes the property with the given name. It does not
  check whether there are types left which use this property. It returns
  true when the named property is succesfully removed. This means it also
  returns true if the property didn't exist in the first place.
  Otherwise it will return false.

  **********************************************************************/

    $this->error="";
    $eproperty=AddSlashes($property);
    $remove_string="drop table prop_$eproperty";
    debug($remove_string);
    $temp=pg_exec($this->connect_id, $remove_string);
    $query_string="delete from properties where name='$eproperty'";
    $temp=pg_exec($this->connect_id, $query_string);
    if ($temp===false) {
      $this->error=pg_errormessage($this->connect_id);
      error("ERROR: PostgreSQL: ".$this->error);
    }
    return 1;
  }
  
  function add_type($type, $implements) {
  /**********************************************************************
  
    This function does not actually create a type, it only serves to
  notify to the system that $type exists and that it implements the
  type or interface given in $implements.
  $type and $implements must be strings of at most 16 characters.

  **********************************************************************/

    $this->error="";
    if ($type && $implements && (strlen($type)<17) && (strlen($implements)<17)) {
      $etype=AddSlashes($type);
      $eimplements=AddSlashes($implements);
      $query_string="insert into types values ('$etype','$eimplements')";
      debug($query_string);
      $temp=pg_exec($this->connect_id, $query_string);
      if ($temp===false) {
        $this->error=pg_errormessage($this->connect_id);
        error("ERROR: PostgreSQL: ".$this->error);
        $result=0;
      } else {
        $result=1;
      }  
    } else {
      $this->error="Wrong format for type or implements";
    }
    return $result;
  }

  function del_type($type, $implements="") {
  /**********************************************************************

    This function notifies the system that either:
  1) A type no longer implements a certain type or interface, or
  2) a type no longer exists.

  **********************************************************************/

    $this->error="";
    $etype=AddSlashes($type);
    if (!$implements) {
      $query_string="delete from types where type='$etype' or implements='$etype'";
    } else {
      $eimplements=AddSlashes($implements);
      $query_string="delete from types where type='$etype' and implements='$etype'";
    }
    debug($query_string);
    $temp=pg_exec($this->connect_id, $query_string);
    if ($temp===false) {
      $this->error=pg_errormessage($this->connect_id);
      error("ERROR: PostgreSQL: ".$this->error);
      $result=0;
    } else {
      $result=1;
    }
    return $result;
  }

}

?>