#################################################################################
#
# $Header: Repository.pm 23-mar-2007.09:29:53 chyu Exp $
#
# Repository.pm
#
# Copyright (c) 2003, 2006, Oracle. All rights reserved.  
#
#    NAME
#      Repository.pm - <one-line expansion of the name>
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YYYY)
#       chyu       03/23/07 - Backport chyu_bug-5404537 from main
#       chyu       07/21/06 - adding the RELEASE_VERSION mechanism to the 
#                             process 
#       ktlaw      07/22/05 - fix filename issue 
#       gsbhatia   07/22/05 - Use getters/setters 
#       gsbhatia   07/16/05 - Add logging support 
#       ktlaw      01/14/05 - add comments 
#       ktlaw      01/11/05 - first cut 
#       ktlaw      01/10/05 - created
################################################################################

package Repository;

use IO::Handle;
use strict;
use Logger;

my $h;

sub getLogger{
  my $self = shift;
  return $self->{'logger'};
}

sub setLogger{
  my ($self, $v) = @_;
  $self->{'logger'} = $v;
}

sub getComps{
  my $self = shift;
  return $self->{'comps'};
}

sub setComps{
  my ($self, $v) = @_;
  $self->{'comps'} = $v;
}

sub getComponentRoot{
  my $self = shift;
  return $self->{'componentRoot'};
}

sub setComponentRoot{
  my ($self, $v) = @_;
  $self->{'componentRoot'} = $v;
}

sub getRoot{
  my $self = shift;
  return $self->getComponentRoot;
}

sub setRoot{
  my ($self, $v) = @_;
  $self->setComponentRoot($v);
}

sub getSQLRoot
{
  my $self = shift ;
  return $self->getComponentRoot ;
}

sub new
{
  my ($pkg) = @_ ;
  my $self = {};
  bless $self, $pkg;
  $self->setComps({}) ;
  bless $self, $pkg;
  $self->setLogger(Logger->new());
  return $self;
}

sub log{
  my ($self, $msg) = @_;
  $self->getLogger->infoln("$msg");
}

sub discoverReleaseVersion{
  my $self = shift;
  my $sqlRoot = $self->getSQLRoot();
  $self->{'release_version'} = "";
  unless (open(OUTPUT_FILE, "$sqlRoot/release_version"))
  {
    return;
  }
  while (<OUTPUT_FILE>)
  {
    if (/\s*(?:(\d+\.\d+\.\d+\.\d+\.\d+.*?))\n/)
    {
      $self->{'release_version'} = $1;
      last;
    }
  }
  close(OUTPUT_FILE);
}

sub getReleaseVersion{
  my $self = shift;
  return $self->{'release_version'};
}

sub init 
{
  my $self = shift ;
  my ($root) = @_ ;
  $self->setComponentRoot($root);
  $self->discoverReleaseVersion();
  # search for component.xml here
  sub findComponent
  {
     my ($file) = @_ ;
     if($file !~ /\#/)
     {
       my $comp = new Component() ;
       my $release_version = $self->getReleaseVersion();
       if ($release_version ne "") {
         $comp->setReleaseVersion($self->getReleaseVersion());
       }
       $comp->setLogger($self->getLogger);
       if($comp->init($file))
       {
         $self->addComponent($comp);
       }
     }``
  }
  my $d = new Directory();
  $d->setPath($self->getComponentRoot); 
  $d->find(\&findComponent,'true','component\.xml$');
}

sub addComponent
{
  my $self = shift ;
  my ($comp) = @_ ;

  $self->getComps->{$comp->getName} = $comp ;
}

#return a list of components
sub getComponents
{
  my $self = shift ;
  return values ( %{$self->getComps} ) ;
}

sub getComponent
{
  my $self = shift ;
  my ($name) = @_ ;
  return $self->getComps->{$name} ;
}

#returns a ordered list of components
sub getComponentsOrdered
{
  my $self = shift ;
  my $score = {} ;
  my @list = $self->getComponents;
  foreach $h (@list)
  {
    $self->computeScore($score,$h);
  }
  sub scoreCmp
  {
    return $score->{$a->getName} cmp $score->{$b->getName} ;
  }
  return sort scoreCmp @list;  
}

sub computeScore
{
  my $self = shift ;
  my ($hash,$comp) = @_ ;
  if( ! defined $comp )
  {
     return 0;
  }
  if( defined $hash->{$comp->getName})
  {
    return $hash->{$comp->getName} ;
  }
  my @deps = keys ( %{$comp->getDependencies} );
  my $depCount = @deps ;
  if( $depCount == 0 )
  {
    $hash->{$comp->getName} = 0 ;
    return 0 ;
  }else
  {
    my $score = 0 ;
    foreach $h (@deps)
    {
      $score = $score + 1 + $self->computeScore($hash,$self->getComponent($h));
    } 
    $hash->{$comp->getName} = $score ;
    return $score ;   
  }
}
sub createAll
{
  my $self = shift ;
  my ($session) = @_ ;
  my @list = $self->getComponentsOrdered;
  $self->create($session,\@list);
}

sub create
{
  my $self = shift ;
  my ($session,$list) = @_ ;
  if(defined $session)
  {
    foreach $h (@$list)
    {
      $h->create($session);
    }
    $session->recompileInvalidObjects();
    $session->pinPLSQL();
    foreach $h (@$list)
    {
      $h->post_create($session); 
      $session->setComponentVersion($h->getName,$h->getVersion);
    } 
    $session->executeCmd("commit;");
    $session->createViewUser();
    $session->setRepositoryVariables();
    foreach $h (@$list)
    {
      $h->outofbox($session); 
    } 
    $session->submitDBMSJobs();
    $session->setRepositoryStatusReady();
  }
}

sub createComponent
{
  my $self = shift ;
  my ($session,$compName) = @_ ;
  my $comp = $self->getComponent($compName);
  if(defined $session && defined $comp)
  {
    $comp->create($session);
    $comp->post_create($session); 
    $session->setComponentVersion($comp->getName,$comp->getVersion);
    $session->executeCmd("commit;");
    $comp->outofbox($session); 
  }
}

sub upgradeAll
{
  my $self = shift ;
  my ($session, $versions) = @_;
  my @list = $self->getComponentsOrdered;
  $self->upgrade($session, $versions, \@list);
}

sub upgrade
{
  my $self = shift ;
  my ($session, $versions, $list) = @_;
  if(defined $session)
  {
    $session->preUpgrade();
    $session->removeDBMSJobs();
    foreach $h (@$list)
    {
      my $version = $versions->{$h->getName} ;
      if(defined $version)
      {
        $h->schema_upgrade($session,$version);
      }else
      {
        $h->create($session);
      }
    }
    foreach $h (@$list)
    {
      my $version = $versions->{$h->getName} ;
      if(defined $version)
      {
        $h->recreate($session);
      }else
      {
        $h->post_create($session);
      }
    }
    $session->recompileInvalidObjects();
    foreach $h (@$list)
    {
      my $version = $versions->{$h->getName} ;
      if(defined $version)
      {
        $h->data_upgrade($session);
      }else
      {
        $h->out_of_box($session);
      }
    }
    $session->submitDBMSJobs();
  }
}

sub upgradeComponent
{
  my $self = shift ;
  my ($session,$compName,$from) = @_ ;
  my $comp = $self->getComponent($compName);
  if(defined $session && defined $comp)
  {
    if(!defined $from)
    {
      #create component as it does not exist in repository
      $self->createComponent($session,$comp);
    }elsif(Component::verCmp($from,$comp->getVersion) > 0)
    {
      $comp->pre_schema_upgrade($session, $from);
      $comp->schema_upgrade($session,$from);
      $comp->recreate($session);
      $comp->pre_data_upgrade($session, $from);
      $comp->data_upgrade($session,$from);
      $session->setComponentVersion($comp->getName,$comp->getVersion);
    }
  }
} 

1;
