# $Id: Model.pm,v 1.1 2004/11/11 19:49:31 jkremer Exp $
# Copyright 2004 Sun Microsystems, Inc., All Rights Reserved.
# Sun Proprietary/Confidential: For Internal Use Only
package Catalog::Model;

use strict;
use Catalog::Entry;
use XML::LibXML;
use base 'Catalog::Entry';
use Data::Dumper;


sub cim_mapping
{
   return 
	  {
		ctrl     => 'CIM_Card',
		fcport   => 'CIM_Card',
		fru      => 'CIM_Card',
		device   => 'CIM_Card',
		disk     => 'CIM_Card',
		pcu      => 'CIM_Card',
		sfp      => 'CIM_Card',
		iom      => 'CIM_Card',
		battery  => 'CIM_Card',
		fan      => 'CIM_Card',
		midplane => 'NWS_Midplane',
		volume   => 'NWS_StorageVolume',
		pool     => 'NWS_StorageVolume',
		vdisk    => 'NWS_StorageVolume'
	  }
}

sub getCIMClassName {
  my ($this, $className) = @_;
  return $this->cim_mapping->{$className} || 'CIM_Card';
}

sub getNWSClassName {
  my ($this, $className) = @_;
  return $this->cim_mapping->{$className} || 'CIM_Card';
}

sub getNWSPhysicalClassName {
  my ($this, $className) = @_;
  my $map = { midplane => 'NWS_Midplane' };
  if ($map->{$className}){
	 return $map->{$className};
  }
  return "CIM_Card";
}

sub isDevice {
  my ($this, $className) = @_;
  if (!$this->{class}->{device}){  # couldn't load model.
	 my $devs = { ctrl=>1,fcport=>1,disk=>1,pcu=>1,sfp=>1,iom=>1,battery=>1,
					  fan=>1,midplane=>1,volume=>1,pool=>1,vdisk=>1
					};
	 return $devs->{$className};
  }
  return $this->isA("device", $className);
}

sub isSystem {
  my ($this, $className)= @_;
}

sub isA {
  my ($this, $isClass, $base) = @_;
  return 1 if ($isClass eq $base);
  my $class = $this->{class}->{$isClass};
  if ($class){
	 my $extends = $class->{extends};
	 if ($extends){
		if (!($isClass eq $extends)){
		  return $this->isA($extends, $base);
		}	
	 }
  }	
  return 0;
}


sub new {
  my ($class, $type, $dir) = @_;

  my $this = { "type"   => $type,
               "entry"  => "model.xml",
					"dir"    => $dir
				 };
  bless($this, "Catalog::Model");
  return $this->loadEntry();
}

sub load {
  my ($this) = @_;
  $this->{class} = {};
  $this->_loadFile($this->{file});
}

sub _loadFile {
  my ($this, $file) = @_;

  my $parser = XML::LibXML->new();
  my $dom;
  eval {
	 $dom  = $parser->parse_file($file);
  };
  if ((!$dom)||($@)){
	 $this->setError("Error parsing XML document element. $@");
	 return;
  }
  my $model = $dom->getDocumentElement();
  foreach my $incElem ($model->findnodes("include")){
	 $this->_loadInclude($incElem);
  }
  foreach my $classElement ($model->findnodes("class")){
	 $this->_loadClass($classElement);

  }
}

sub _loadInclude {
  my ($this, $incElem) = @_;

  my $file = $incElem->getAttribute("file");
  my $path = $this->{dir}.$file;

  if (-f $path){
	 $this->_loadFile($path);
  }
  else {
	 $path = $this->getCommonDir() . $file;
	 if (-f $path){
		$this->_loadFile($path);
	 }
	 else {
		$this->setError("Error including file $path.");
	 }
  }
}

sub _loadClass {
  my ($this, $classElement) = @_;
  my $cname = $classElement->getAttribute("name");
  my $class = $this->{class}->{$cname};

  if (!$class){
	 $class = { name     => $classElement->getAttribute("name"),
					property => {},
					extends  => $classElement->getAttribute("extends"),
					abstract => $classElement->getAttribute("abstract")
				 };
	 print "Create class " . $class->{name} . "\n";
  }
  else {
	 $class->{abstract} = $classElement->getAttribute("abstract");
  }	

  foreach my $pelem ($classElement->findnodes("property")){
	 $this->_loadProperty($class, $pelem);
  }
  $this->{class}->{$cname} = $class;
}

sub _loadProperty {
  my ($this, $class, $pelem) = @_;
  my $pname    = $pelem->getAttribute("name");
  my $prop     = {};
  foreach my $att ($pelem->attributes()) {
	 $prop->{$att->name()} = $att->value();
  }
  my $vref = $prop->{valueRef};
  if ($vref){
	 $prop->{value} = $this->{value}->{$vref};
	 $prop->{valueMap} = $this->{valueMap}->{$vref};
  }
  else {
	 my $value    = [];
	 my $valueMap = {};
	 foreach my $val ($pelem->findnodes("value")){
		my $map = $val->getAttribute("map");
		if ($map){
		  $valueMap->{$map} = $val->textContent();
		}
		else {
		  push(@$value, $val->textContent());
		}
	 }
	 $prop->{value}    = $value;
	 $prop->{valueMap} = $valueMap;
	 my $vdef = $prop->{valueDef};
	 if ($vdef){
		$this->{value}->{$vdef}    = $value;
		$this->{valueMap}->{$vdef} = $valueMap;
	 }
  }

  $class->{property}->{$pname} = $prop;
}

sub genCode {
  my ($this, $args) = @_;

  my $classes = $this->{class};
  my $package = $args->{package} ||
	 "com.sun.netstorage.fm.storade.resource.report";

  foreach my $className (keys %$classes){
	 my $class = $classes->{$className};
	 my $extends = $class->{extends} || "ReportClass";
	 open (J, ">$className.java");
	 print J "package $package;\n";
	 print J "public class $className extends $extends\n{\n";
	 print J "  public $className(){\n";
	 print J "    super(\"$className\");\n";
	 print J "  }\n";
	 print J "  public $className(String name){\n";
	 print J "    super(\"$className\", name);\n";
	 print J "  }\n";

	 my $props = $class->{property};
	 foreach my $pname (keys %$props){
		my $p = $props->{pname};
		print J "  public String get$pname(){\n";
		print J "    return getProperty(\"$pname\");\n";
	   print J "  }\n";
		print J "  public void set$pname(String value){\n";
		print J "    setProperty(\"$pname\", value);\n";
		print J "  }\n";
	 }

	 print J "} // class $className\n";
	 close (J);
  }
}

1;
