do "core_defines.pl";

do "config.pl";

# set autoflush for STDOUT
select(STDOUT);
$|=1;

#####################################################################
# package core
# handles core installation
#####################################################################
package core;

sub new {
  my ($type, $config_file, $config) = @_;
  my $self = bless {}, $type;
  $self->{config_file} = $config_file;
  $self->{config} = $config;
  ::trace(4, "core new:config_file=$self->{config_file}");
  return $self;
}

#######################################################################
### create_log ###
#######################################################################
sub create_log{
  my $self = shift;
  my $mode = shift;
  # check if use count
  $::logfile="/tmp/mwcore_$mode.log_$$";
  my $date=`date`;chomp($date);
  open(LOGFILE,">$::logfile")||die "Cannot create logfile $::logfile: $!\n";
  print LOGFILE "$::headline";
  print LOGFILE "       MainWin Standard System Core $mode log\n\n";
  print LOGFILE "User:  $::username\n";
  print LOGFILE "Host:  $::hostname\n";
  print LOGFILE "Date:  $date\n";
  print LOGFILE "$::headline\n\n";
  close(LOGFILE);
}

# if core services were already installed, returns 0
# if installation is corrupt - returns -1
# if core services are not installed - returns 1
sub is_core_installed {
  ::trace(4, "in is_core_installed");
  my $self = shift;
  if (!-f $self->{config_file}){ # config_file does not exist
    return 0;
  }
  if (-z $self->{config_file}){ # config_file exists but is empty
    return 0;
  }
  
  system("chmod u+w $self->{config_file} 2> /dev/null");
  ::trace(4, "is_installed: config_file=$self->{config_file}\n");
  
  my $installed_core_path = $self->{config}->get_path_to_core();
  if ($installed_core_path eq "") { #config_file exists but is not valid
    return 0;
  }
  
  if (!-d $installed_core_path ||
      ::is_dir_empty($installed_core_path)) { #installation directory in config_file not valid
    return -1;
  }
  
  $self->{installed_core_path}=$installed_core_path;
  return 1;
}

# reads core version from new installation file and returns it
sub get_core_version {
  ::trace(4, "in get_core_version");
  my $self = shift;
  my $file = shift;
  
  if (! open (FILE, $file))
    {
      ::printlog("Error: Failed to open file '$file': $!.\n");
      print STDERR "Error: Failed to open file '$file': $!.\n"; ::my_exit()};
  
  my @lines = <FILE>;
  close(FILE);
  chomp ($lines[0]);
  return $lines[0];
}

sub get_installed_core_version {
  my $self = shift;
  my $inst_dir = $self->{config}->get_path_to_core();
  return $self->get_core_version("$inst_dir/mw/bin/tools/$::version_file");
}

# Compares new Core version with the existing one from config_file,
# set core->{new_ver_compatible} to 1 if the new core version will save
# backward compatibility and to 0 if it breaks compatibility
# Returns 1 if upgrade needed, 0 if not
sub is_upgrade_required {
  ::trace(4, "in is_upgrade_required");
  my $self = shift;
  $self->{new_core_version} = shift;
  my $repair = shift;
  $self->{installed_core_version} = $self->get_installed_core_version();
  
  ($new_compat_ver,$new_build_ver) =
    split(/\./,$self->{new_core_version});
  ($installed_compat_ver,$installed_build_ver) =
    split(/\./,$self->{installed_core_version});
  
  if ($new_compat_ver > $installed_compat_ver) {
    # upgrade needed, but it will break backward compatibility
    $self->{new_ver_compatible}=0;
    return 1; 
  }
  
  # TO DO move this error outside of the function
  elsif ($new_compat_ver < $installed_compat_ver) {
    ::printlog("Error: The version of $::core_name you wish to install ($self->{new_core_version}) is older than the currently installed version ($self->{installed_core_version}). Also, installed applications will not work with version $self->{new_core_version}.\nIf you wish to install the older version of $::core_name, you must first uninstall the current installation.\n");
    print STDERR "Error: The version of $::core_name you wish to install ($self->{new_core_version}) is older than the currently installed version ($self->{installed_core_version}). Also, installed applications will not work with version $self->{new_core_version}.\nIf you wish to install the older version of $::core_name, you must first uninstall the current installation.\n";
    ::my_exit();
  }
  
  elsif (($new_build_ver > $installed_build_ver) ||
	 (($new_build_ver == $installed_build_ver) &&
	  $repair)) {
    # upgrade required, and backward compatibility will be saved
    $self->{new_ver_compatible}=1;
    return 1;
  }
  
  return 0;  
}

# This function asks user if he wants to upgrade Core Services.
# If compatibility will be broken by upgrade, it prints list of application
# that will no longer work.
# If user accepts or compatibility is not broken - show to user the list
# of applications we have to kill in order to upgrade
# if user accepts to kill this applications return 1, otherwise return 0
sub is_upgrade_accepted {
  ::trace(4, "in is_upgrade_accepted");
  my $self = shift;
  my $install_dir = shift;
  my $answer;
  ::printlog("Upgrading $::core_name from version $self->{installed_core_version} to version $self->{new_core_version}.\n");
  print STDERR "Upgrading $::core_name from version $self->{installed_core_version} to version $self->{new_core_version}.\n"; 
  
  if (! $self->{new_ver_compatible}){ # backward compatability will be broken
    ::printlog("Warning: The new version of $::core_name is not compatible with the currently installed application(s) that depend on it.\nIf you choose to upgrade $::core_name, these applications will no longer work.\n");
    print STDERR "Warning: The new version of $::core_name is not compatible with the currently installed application(s) that depend on it.\nIf you choose to upgrade $::core_name, these applications will no longer work.\n";

    ::printlog("Would you like to continue upgrading? [y/n]: ");
    print STDERR "Would you like to continue upgrading? [y/n]: ";
    
    if (! ::user_agrees()) {
      return 0;
    }
  }
  
  @applications = `$::show_core_apps $install_dir`;
  if ($?) {
    ::printlog("Error: Failed to retreive list of running applications that depend on $::core_name.\n");
    print STDERR "Error: Failed to retreive list of running applications that depend on $::core_name.\n";
    ::my_exit();
  }
  if (@applications > 0) { #there are applications to kill
    ::printlog("In order to proceed, the following applications must be killed:\n");
    print STDERR "In order to proceed, the following applications must be killed:\n";
    foreach $app (@applications) {
      chomp($app);
      ::printlog("*\t$app\n");
      print STDERR "*\t$app\n";
    }
    ::printlog("Do you want to continue with the installation? [y/n]: ");
    print STDERR "Do you want to continue with the installation? [y/n]: ";
    return (::user_agrees());
  }
  
  return 1; # no applications to kill, so the user shouldn't have any problems
}

# returns 1 if user agrees to uninstall core services,
# 0 if he doesn't want to.
sub is_uninstall_accepted {
  ::trace(4, "in is_uninstall_accepted");
  my $self = shift;
  ::printlog("Warning: Uninstalling $::core_name will stop applications that depend on it from working.\nAre you sure you want to uninstall $::core_name? [y/n]: ");
  print STDERR "Warning: Uninstalling $::core_name will stop applications that depend on it from working.\nAre you sure you want to uninstall $::core_name? [y/n]: ";
  return (::user_agrees());
}

# returns 1 if user agrees to uninstall core services,
# 0 if he doesn't want to.
sub is_unsetup_accepted {
  ::trace(4, "in is_unsetup_accepted");
  my $self = shift;
  ::printlog("Warning: Removing $::core_name setup will stop applications that depend on it from working on this host.\nAre you sure you want to continue? [y/n]: ");
  print STDERR "Warning: Removing $::core_name setup will stop applications that depend on it from working on this host.\nAre you sure you want to continue? [y/n]: ";
  return (::user_agrees());
}

# if receives a directory - check that it is valid, if not,
# asks user for a directory and checks it.
sub get_dir {
  ::trace(4, "in get_dir");
  my $self = shift;
  my $dir_type = shift;
  my $root_access_needed = shift;
  my $defaultdir = shift;
  my $targetdir = shift;
  my $true = 1;
  my $created_dir = 0;
  my $first_time = 1;
  while ($true) {
    if (!$first_time || !$targetdir) {
      $targetdir = $defaultdir if (!$targetdir);
      $targetdir = $self->get_dir_from_user($dir_type, $targetdir);
    }
    $first_time = 0;
    if (-f $targetdir && !-d $targetdir) {
      ::printlog("Warning: The specified $dir_type directory '$targetdir' is a file and not a directory.\n");
       print STDERR "Warning: The specified $dir_type directory '$targetdir' is a file and not a directory.\n";
      exit 1 if ($::automatic);
      ::printlog("Do you want to remove this file? [y/n]: ");
      print STDERR "Do you want to remove this file? [y/n]: ";
      if (::user_agrees()) {
	if (!unlink($targetdir)) {
	  ::printlog("Error: Failed to remove '$targetdir': $!\n");
	  print STDERR "Error: Failed to remove '$targetdir': $!\n";
	  ::my_exit();
	}
      }
      else {
	next;
      }
    }
    if (!-d $targetdir) {
      if ($::automatic){
	::my_exit() if (::create_dir($targetdir));
	$created_dir = 1;
      }
      else{
	::printlog("Directory '${targetdir}' does not exist.\n\t[1] Retype path\n\t 2  Create directory\n\t 3  Exit\nPlease select one of the above: ");
	print STDERR "Directory '${targetdir}' does not exist.\n\t[1] Retype path\n\t 2  Create directory\n\t 3  Exit\nPlease select one of the above: ";
	$answer=<STDIN>;chomp($answer);
	::printlog("$answer\n");
	$answer=~ s/^\s+//;#remove spaces at the begining
	$answer=~ s/\s+$//;#remove spaces at the end
	if ($answer eq "") {$answer=1;}
	if (($answer < 1) || ($answer > 3)) {
	  ::printlog("'$answer' is not a valid option.\n");
	  print STDERR "'$answer' is not a valid option.\n";
	  next;
	}
	if ($answer == 1) {
	  next;
	}  
	elsif ($answer == 3) {::my_exit();}
	elsif($answer == 2) {
	  ::my_exit() if (::create_dir($targetdir));
	  $created_dir = 1;
	}
      }
    }
    if ($root_access_needed && ! $self->check_if_root_access($targetdir)) {
      #no root access
      if ($created_dir) {
	system("/bin/rm", "-rf", $targetdir);
	::printlog("Deleted directory '$targetdir'.\n");
	print STDERR "Deleted directory '$targetdir'.\n";
      }
      ::my_exit() if ($::automatic);
      next;
    }
    # Only installation directory has to be empty.
    if (! ::is_dir_empty($targetdir) && ($dir_type eq "installation")) {
      print STDERR "Warning: The specified $dir_type directory '$targetdir' is not empty.\n";
      ::printlog("Warning: The specified $dir_type directory '$targetdir' is not empty.\n");
      ::my_exit() if ($::automatic);
      next;     
    }
    if (! -w $targetdir) {
      ::printlog("Warning: The specified $dir_type directory '${targetdir}' does not have write permission.\nYou may change directory permissions and try again, or enter a new $dir_type location.\n");
      print STDERR "Warning: The specified $dir_type directory '${targetdir}' does not have write permission.\nYou may change directory permissions and try again, or enter a new $dir_type location.\n";
      ::my_exit() if ($::automatic);
      next;
    }
    $true = 0;
  } # end while
  return $targetdir;
}

sub get_dir_from_user {
  ::trace(4, "in get_dir_from_user");
  my $self = shift;
  my $dirtype = shift;
  my $targetdir = shift;
  my $true = 1;
  my $answer = undef;
  
  while ($true) {
    ::printlog("Please enter path to $dirtype directory or (a)bort <default=$targetdir>: ");
    print STDERR "Please enter path to $dirtype directory or (a)bort <default=$targetdir>: ";
    $answer = <STDIN>;
    chomp($answer);
    ::printlog("$answer\n");
    $answer =~ s/^\s+//;#remove spaces in the begining of targetdir
    $answer =~ s/\s+$//;#remove spaces in the end of targetdir
    if ($answer eq "a") { ::my_exit(); }
    elsif ($answer ne "") {
      $targetdir = $answer;
    }
    if (($targetdir =~ /\*/) || 
	($targetdir =~ /\\/)) {
      ::printlog("The specified $dirtype directory '$targetdir' is not a valid directory.\n");
      print STDERR "The specified $dirtype directory '$targetdir' is not a valid directory.\n";
      next;
    }
    else {
      $true = 0;
    }
  }
  
  @dirs=split(/\//,$targetdir);
  if ($dirs[0] eq "~"){
    shift(@dirs);
    unshift(@dirs,$ENV{'HOME'});
    $targetdir=join("/",@dirs);
  }
  elsif(($dirs[0] eq ".") || ($dirs[0] eq "..")){
    my $pwd = `pwd`;
    chomp($pwd);
    unshift(@dirs,$pwd);
    $targetdir=join("/",@dirs);
  }
  return $targetdir;
}

sub check_if_root_access {
  ::trace(4, "in check_if_root_access");
  my $self = shift;
  my $targetdir = shift;
  #test for root installation if the target directory have root access
  system("umask 0;/bin/touch $targetdir/testfile 2> /dev/null");
  if ($? != 0 ){
    ::printlog("Warning: Cannot install in directory '$targetdir' - no write permission.\nYou may change directory permission and try again, or enter a new installation location.\n");
    print STDERR "Warning: Cannot install in directory '$targetdir' - no write permission.\nYou may change directory permission and try again, or enter a new installation location.\n";
    return 0;
  }
  
  $trash=`/bin/ls -l $targetdir/testfile`;
  ($trash1,$trash2,$tmpuser,@trash3)=split(/\s+/,$trash);
  if ($tmpuser eq "nobody"){
    ::printlog("No root access to '$targetdir'.\nSuper user on this host ($::hostname) does not have access rights to the above mounted location.\nTo install in this location, set up the file server (that exports this directory) to allow root access from host '$::hostname'.\nAlternatively, specify an installation directory on a local disk.\n");
    print STDERR "No root access to '$targetdir'.\nSuper user on this host ($::hostname) does not have access rights to the above mounted location.\nTo install in this location, set up the file server (that exports this directory) to allow root access from host '$::hostname'.\nAlternatively, specify an installation directory on a local disk.\n";
    return 0;
  }
  
  system("/bin/rm -f $targetdir/testfile 2> /dev/null");  
  return 1;
}

# asks user to supply a user name that will start and stop the core
# services. return the user name.
sub get_special_user {
  ::trace(4, "in get_special_user");
  my $self = shift;
  my $user = shift;
  my $true = 1;
  my $first_time = 1;
  
  if (!$user) {
      ::printlog("'nThe MSC administrator has special privileges in the realm of the MSC. This\nincludes being the only user who may execute certain Visual MainWin system\noperations, such as manually stopping and starting the MSC services, and\noperations that modify secured system data (like DCOM security settings and\ncertain Registry entries that control the local host settings).\n\nPlease enter the user designated to be the MSC administrator on this host. [root], a - abort:");

    print STDERR "\nThe MSC administrator has special privileges in the realm of the MSC. This\nincludes being the only user who may execute certain Visual MainWin system\noperations, such as manually stopping and starting the MSC services, and\noperations that modify secured system data (like DCOM security settings and\ncertain Registry entries that control the local host settings).\n\nPlease enter the user designated to be the MSC administrator on this host. [root], a - abort:";
  }
  
  while ($true) {
    if (!$first_time || !$user) {
      ::printlog("Please enter the user designated to be the MSC administrator on this host. [$::username], a - abort: ");
      print STDERR "Please enter the user designated to be the MSC administrator on this host. [$::username], a - abort: ";
      $user = <STDIN>;
      chomp($user);
      ::printlog("$user\n");
      $user =~ s/^\s+//;#remove spaces in the begining of user
      $user =~ s/\s+$//;#remove spaces in the end of user
      
      
      if ($user eq "a") { 
	::my_exit(); 
      }
      elsif ($user eq "") {
	$user = $::username;
	$true = 0;
	next;
      }
    }
    $first_time = 0;
    if (getpwnam($user) eq "") {
      ::printlog("*** The specified user does not exist.\n");
      print STDERR "*** The specified user does not exist.\n";
      next;
    }
    else {
      $true = 0;
    }
  }
  
  return $user;
}

sub complete_config_info {
  my $self = shift;
  my ($install_ref, $data_ref, $user_ref) = @_;

  if (! $$install_ref) {
    while(1) {
      ::printlog("Please enter full path to $::core_name installation directory or 'S' to skip this step: ");
      print STDERR "Please enter full path to $::core_name installation directory or 'S' to skip this step: ";
      $$install_ref = <STDIN>;
      chomp($$install_ref);
      ::printlog("$$install_ref\n");
      last if ($$install_ref =~ /^[sS]$/); # skip this step
      if (! -d $$install_ref || ::is_dir_empty($$install_ref) || ! -f "$$install_ref/mw/setmwruntime") {
	::printlog("The specified installation directory '$$install_ref' is not a valid directory.\n");
	print STDERR "The specified installation directory '$$install_ref' is not a valid directory.\n";
	next;
      }
      last;
    }
  }
  
  if (!$$data_ref) {
    while(1) {
      ::printlog("Please enter full path to $::core_name data directory or 'S' to skip this step: ");
      print STDERR "Please enter full path to $::core_name data directory or 'S' to skip this step: ";
      $$data_ref = <STDIN>;
      chomp($$data_ref);
      ::printlog("$$data_ref\n");
      last if ($$data_ref =~ /^[sS]$/); # skip this step
      if (! -d "$$data_ref/$::hostname" || ::is_dir_empty($$data_ref)) {
	::printlog("The specified data directory '$$data_ref' is not a valid directory.\n");
	print STDERR "The specified data directory '$$data_ref' is not a valid directory.\n";
	next;
      }
      last;
    }
  }

  if (! $$user_ref) {
    while(1) {
      ::printlog("Please enter MainWin administrator [$::username]: ");
      print STDERR "Please enter MainWin administrator [$::username]: ";
      $$user_ref = <STDIN>;
      chomp($$user_ref);
      ::printlog("$$user_ref\n");
      if ("$$user_ref" eq ""){$$user_ref=$::username;}
      if (getpwnam($$user_ref) eq "") {
        ::printlog("'$user_ref' is not a valid user name.\n");
        print STDERR "'$user_ref' is not a valid user name.\n";
        next;
      }
      last;
    }
  }

}

# install core services:
# 1. installs - copy files to Core services installation directory
# chmod and chown files
# 2. setup - create script that will run at boot time
# create script that starts core only as special user
# 3. start services - stop services, if we are upgrading
# start services
# returns 0 on success, 1 on error, -1 on warning
sub install {
  ::trace(4, "in install");
  my $self = shift;
  my $install_dir = shift;
  my $data_dir = shift;
  my $username = shift;
  my $upgrade = shift;
  
  # installs core services - copy files to installation directory
  if ($self->core_install($install_dir, $data_dir, $username) != 0) {
    return 1;
  }
  # Run installCompiler for linux
  if ($::MWOS eq "linux"){
    print STDERR "Running installCompiler\n";
    system("$::fulldir/../../../tools/installCompiler $install_dir MSC");
  }

  
  #print  "Running setup: $install_dir/mw/bin/setup.mwcore -instdir $install_dir -datadir $install_dir/mwcoredata -adm $username -not_start\n";
  system("$install_dir/mw/bin/setup.mwcore -instdir $install_dir -datadir $install_dir/mwcoredata -adm $username -not_start");
  if ($? != 0){
      print STDERR " Failed setup  MainWin System Core\n";
  }
  #print "Running command: /usr/bin/mwadm start\n";
  system("/usr/bin/mwadm start 2> /dev/null");
  if ($? != 0){
      print STDERR " Failed to start MainWin System Core\n";
  }
  #print "Running command:$install_dir/mw/bin/tools/core_hook3.sh $username $install_dir\n";
  system("$install_dir/mw/bin/tools/core_hook3.sh $username $install_dir 2> /dev/null");
  if ($? != 0){
      print STDERR " Failed core_hook3 MainWin System Core\n";
  }
  
  return 0;
  
}

# sets core services on a machine:
# 1. setup - create script that will run at boot time
# create script that starts core only as special user
# 2. start services - stop services, if we are upgrading
# start services
# returns 0 on success, 1 on error, -1 on warning
sub setup {
  my $self = shift;
  my $install_dir = shift;
  my $data_dir = shift;
  my $username = shift;
  my $do_start = shift;
  
  # sets core system on machine - starts deamons at boot,
  # create configuration file
  if ($self->machine_setup($install_dir, $data_dir, $username) != 0) {
    return 1;
  }
  
  # start core services
  if($do_start){
    if ($self->start_services(0, $install_dir, $data_dir, $username) != 0) {
      return -1;
    }
  }
  
  return 0;
}

sub core_install {
  my $self = shift;
  my $install_dir = shift;
  my $data_dir = shift;
  my $username = shift;
  
  ::printlog("Copying files ... ");
  print STDERR "Copying files ... ";
  
  # copy files from cd to installation directory
  #::trace(2, "chdir $install_dir");
  chdir("$install_dir");
  @core_files=("$::MWCONFIG_NAME.tgz","generic.tgz");
  foreach $file (@core_files){ 
      # print STDERR "COMMAND: umask 0;MWLIBDIR=$::fulldir/exe/$::MWCONFIG_NAME:$SHLIB_PATH;export MWLIBDIR;cat $::fulldir/../../$file|$::fulldir/../../../exe/$::MWCONFIG_NAME/mwzip -d|/bin/tar xfo -\n";
      system("umask 0;MWLIBDIR=$::fulldir/../../../exe/$::MWCONFIG_NAME;export MWLIBDIR;cat $::fulldir/../../$file|$::fulldir/../../../exe/$::MWCONFIG_NAME/mwzip -d|/bin/tar xfo -");
      if ($? != 0){
	  ::printlog("Failed.\nError: Failed to extract '$::fulldir/../../$file' to directory '$install_dir'.\n");
	  print STDERR "Failed.\nError: Failed to extract '$::fulldir/../../$file' to directory '$install_dir'.\n"; return 1
      }
      
  }
  
  ::trace(2, "chdir $::curdir");
  chdir("$::curdir");
  
  ::printlog("Done.\n");
  print STDERR "Done.\n";

  ::printlog("Setting file permissions ... ");
  print STDERR "Setting file permissions ... ";
  my $group;
  if ($::mwos eq "AIX") {
      $group = "system";
  }
  elsif ($::mwos eq "Linux") {
      $group = "root";
  }
  else {
      $group = "other";
  }
  ::trace(2, "/bin/chown -Rh root:$group $install_dir 2> /dev/null");
  system("/bin/chown -Rh root:$group $install_dir 2> /dev/null");
  $status=$?;
  if ($status != 0){
      ::printlog("Failed.\nError: Failed to change attributes of installed files.\n");
      print STDERR "Failed.\nError: Failed to change attributes of installed files.\n"; return 1;
  }
  
  # Set permissions to 755 for all executable files and directories
  system("find $install_dir \\( -perm -u+x -o -type d \\) -print | /bin/sed -e 's:\^:\":' -e 's:\$:\":' | xargs /bin/chmod u=rwx,g=rx,o=rx,u-s,g-s 2>/dev/null");
  if ($? != 0)
    {::printlog("Failed.\nError: Failed to change attributes of installed files.\n");
      print STDERR "Failed.\nError: Failed to change attributes of installed files.\n"; return 1;}
 
  # Set permissions to 644 for all non-executable files
  system("find $install_dir \! -perm -u+x -print | /bin/sed -e 's:\^:\":' -e 's:\$:\":' | xargs /bin/chmod u=rw,g=r,o=r 2>/dev/null");
  if ($? != 0)
    {
      ::printlog("Failed.\nError: Failed to change attributes of installed files.\n");
     print STDERR "Failed.\nError: Failed to change attributes of installed files.\n"; return 1;}
 
  # change attributes and ownership of files THIS is done by SETUP
  #if (system($::hook1, $username, $install_dir))
   # {
    #  ::printlog("Failed.\nError: Failed to change attributes of installed files.\n");
     # print STDERR "Failed.\nError: Failed to change attributes of installed files.\n"; return 1;
    #}
  ::printlog("Done\n");
  print STDERR "Done.\n";
  return 0;
}

sub machine_setup {
  my $self = shift;
  my $install_dir = shift;
  my $data_dir = shift;
  my $username = shift;
  my $endpoint = "dynamic";
  my $secret_created=0;
  ::printlog("Configuring $::core_name ... ");
  print STDERR "Configuring $::core_name ... ";
  ::trace(4, "in machine_setup, install_dir=$install_dir,data_dir=$data_dir,username=$username");

  # change attributes and ownership of files(the same like in core_install, for the case the install.mwcore was not run)
  if (system($::hook1, $username, $install_dir))
    {
      ::printlog("Failed.\nError: Failed to change attributes of installed files.\n");
      print STDERR "Failed.\nError: Failed to change attributes of installed files.\n"; return 1;
    }
  
  # create script that runs in boot time and starts core services
  if (system($::create_boot_script, "$install_dir/mw/bin/$::start_core",$username, $install_dir, $data_dir))
  {::printlog("Failed.\nError: Failed to create boot script.\n");
   print STDERR "Failed.\nError: Failed to create boot script.\n"; return 1;}
  
  # create logs directory
  if (system("mkdir -p \"${data_dir}/logs\""))
  {
      ::printlog("Failed.\nError: Failed to create directory '${data_dir}/logs'.\n");
      print STDERR "Failed.\nError: Failed to create directory '${data_dir}/logs'.\n"; return 1;}
  
  if (system("cd /usr/bin;rm -f mwadm; ln -s $install_dir/mw/bin/mwadm mwadm;")){
      ::printlog("Failed.\nError: Failed to create symbolic link /usr/bin/mwcore -> $install_dir/mw/bin/mwcore .\n");
      print STDERR "Failed.\nError: Failed to create symbolic link /usr/bin/mwcore -> $install_dir/mw/bin/mwcore.\n"; return 1;}
  
  # change attributes and ownership of files
  if (system($::hook2, $username, $install_dir, $data_dir))
  {
      ::printlog("Failed.\nError: Failed to change attributes of installed files.\n");
      print STDERR "Failed.\nError: Failed to change attributes of installed files.\n"; return 1;}
  
  # update configuration file
  if ($self->{config}->update_config_file($install_dir, $data_dir, $username, $endpoint) != 0) {
      return 1;
  }
  ::printlog("Done.\n");
  print STDERR "Done.\n";
  
  

  if (!$secret_created){ # create empty secret file
      system("touch  $data_dir/../secret");
      $secret_created=1;
  }
  if ($secret_created && ($::username ne $username)){
    system("chown $username $data_dir/../secret");
  }
  if (! -s "$data_dir/secret"){
    system("ln -s $data_dir/../secret $data_dir/secret");
  }
  
  system("chmod 0600 $data_dir/../secret");
  system("chmod 0600 $data_dir/secret");
  
  return 0;
}

# return 1 on error, 0 on success
sub start_services {
  my $self = shift;
  my $upgrade = shift;
  my $install_dir = shift;
  my $data_dir = shift;
  my $username = shift;
  
  # in case of upgrade, stop core services first
  if ($upgrade) {
    if ($self->stop_services($username, $install_dir, $data_dir) != 0) {
      return 1;
    }
  }
  ::printlog("Starting $::core_name services ... ");
  print STDERR "Starting $::core_name services ... ";
  
  # start core services 
  ::trace(2, "running $install_dir/mw/bin/$::start_core start $username $install_dir $data_dir");
  system("$install_dir/mw/bin/$::start_core start $username $install_dir $data_dir 2> /var/tmp/err$$");
  if ($? != 0)
    {
      @err=`cat /var/tmp/err$$`; 
      system("rm -f /var/tmp/err$$ 2> /dev/null");
      ::printlog("Failed.\n@err");
      print STDERR "Failed.\n@err";
      return 1;
    }
  ::printlog("Done\n");
  print STDERR "Done.\n";
  ::printlog("Running $::hook3 $username $install_dir ..."); 
  system("$::hook3 $username $install_dir 2> /var/tmp/err$$");
  if ($? != 0)
  {
      @err=`cat /var/tmp/err$$`;
      system("rm -f /var/tmp/err$$ 2> /dev/null");
      ::printlog("Failed.\n@err");
      return 1;
  }
  ::printlog("Done\n");
  return 0;
}

# returns 1 on error, 0 on success, -1 on warning
sub uninstall {
  ::trace(4, "in uninstall");
  my $self = shift;
  my $install_dir = shift;
  my $data_dir = shift;
  my $user = shift;
  my $status = 0;
 
  # stop core services
  $status = $self->stop_services($user, $install_dir, $data_dir);
  
  # un-setup core services - delete configuration file, data area and 
  # script that starts services at boot
  if ($self->machine_unsetup($data_dir) != 0) {
    return 1;
  }
  
  # deletes installation directory
  if ($self->core_uninstall($install_dir) != 0) {
    return 1;
  }

  return $status;
  
}

# returns 1 on error, 0 on success, -1 on warning
sub unsetup {
  ::trace(4, "in unsetup");
  my $self = shift;
  my $user = shift;
  my $install_dir = shift;
  my $data_dir = shift;
  my $status = 0;
  
  # stop core services
  $status = $self->stop_services($user, $install_dir, $data_dir);
  
  # un-setup core services - delete configuration file, data area and 
  # script that starts services at boot
  if ($self->machine_unsetup($data_dir) != 0) {
    return 1;
  }
  return $status;
}

# return 1 on error, 0 on success
sub stop_services {
  my $self = shift;
  my $username = shift;
  my $install_dir = shift;
  my $data_dir = shift;
  ::printlog("Stopping $::core_name services ... ");
  print STDERR "Stopping $::core_name services ... ";
  
  # stop core services 
  print STDERR "Run $install_dir/mw/bin/$::start_core stop -f $username $install_dir $data_dir 2> /var/tmp/err$$\n";
  system("$install_dir/mw/bin/$::start_core stop -f $username $install_dir $data_dir 2> /var/tmp/err$$");
  sleep 5;
  if ($? != 0)
  {
      @err=`cat /var/tmp/err$$`; 
     # system("rm -f /var/tmp/err$$ 2> /dev/null");
      ::printlog("Failed.\n@err");
      print STDERR "Failed.\n@err";
      return 1;
  }
  ::printlog("Done.\n");
  print STDERR "Done.\n";
  return 0;
}

sub machine_unsetup {
  my $self = shift;
  my $data_dir = shift;
  my $status = 0;
  my $error = "";
  ::printlog("Unsetting $::core_name ... ");
  print STDERR "Unsetting $::core_name ... ";
  
  # delete script that runs at boot
  if (($status = $self->delete_boot_script()) != 0) {
    $error = "Error: Failed to delete boot script.\n";
  }
  
  # delete config file
  if ($status = system("/bin/rm", "-f", $::config_file)) {
    $error .= "Error: Failed to delete file '$::config_file'.\n";
  }
  
  # delete data directory only if data_dir defined
  if ($data_dir !~ /^[sS]$/){
    #delete secret file
    if ($status=system("/bin/rm -f $data_dir/../secret")){
      $error .= "Error: Failed to delete $::core_name security file '($data_dir/../secret)'.\n";
    }
    if ($status = system("/bin/rm", "-rf", $data_dir)) {
      $error .= "Error: Failed to delete $::core_name data directory '($data_dir)'.\n";
    }
    # if no more hosts use data dir remove it
    $data_dir=~s/\/$::hostname//; 
    if (::is_dir_empty("$data_dir")){
      system("/bin/rm", "-rf", "$data_dir");
    }
  }
  # remove link to real mwadm
  if (-e "/usr/bin/mwadm" ){
   system("/bin/rm -f /usr/bin/mwadm");
  }

  if ($status == 0) {
    ::printlog("Done.\n");
    print STDERR "Done.\n";
  }
  else {
    ::printlog("Failed.\n$error");
    print STDERR "Failed.\n$error";
  }
  
  return $status;
}

# returns 1 on error, 0 on success
sub core_uninstall {
  my $self = shift;
  my $install_dir = shift;
  ::printlog("Removing files ... ");
  print STDERR "Removing files ... ";
  
  # delete installation dir
  if (system("/bin/rm", "-rf", $install_dir,$::tmp_core_dir))
    {
      ::printlog("Failed.\nError: Failed to delete $::core_name installation directory '($install_dir)'.\n");
      print STDERR "Failed.\nError: Failed to delete $::core_name installation directory '($install_dir)'.\n"; return 1;
    }
  ::printlog("Done.\n");
  print STDERR "Done.\n";
  return 0;
}

# returns 1 on error, 0 on success
sub delete_boot_script {
  ::trace(4, "in delete_boot_script");
  my $self = shift;
  if ($::mwos eq "SunOS") {
    if (!unlink ("/etc/rc2.d/S99mwcore_services"))
      {return 1;}
  }
  elsif ($::mwos eq "Linux") {
    if (!unlink ("/etc/rc.d/rc3.d/S99mwcore_services", 
		 "/etc/rc.d/rc5.d/S99mwcore_services",
		 "/etc/rc.d/init.d/mwcore_services"))
      {return 1;}
  }      
  elsif ($::mwos eq "HP-UX") {
    if (!unlink ("/sbin/init.d/mwcore_services",
		 "/sbin/rc3.d/S99mwcore_services"))
      {return 1;}
  }
  elsif ($::mwos eq "AIX") {
    if (!unlink ("/etc/rc.mwcore_services"))
      {return 1;}
  }      
  return 0;
}

1;

#######################################################################
# package main
#######################################################################
package main;

sub my_exit {
  my $message = shift;
  if ($message) {
    ::printlog("$message\n");
    print STDERR $message, "\n";
  } else {
    ::printlog("Installation aborted.\n");
    print STDERR "Installation aborted.\n";
  }
  exit(1);
}
# create_dir create directory that get as parameter
# return 0 in success, 1 - in failure
sub create_dir{
  my $targetdir=shift;
  ::printlog("Creating directory '${targetdir}' ... ");
  print STDERR "Creating directory '${targetdir}' ... ";
  system("/bin/mkdir -p ${targetdir} 2> /dev/null");
  if ($? != 0) {
    ::printlog("Failed.\nCould not create directory '${targetdir}'.\n");
    print STDERR "Failed.\n";
    print STDERR "Could not create directory '${targetdir}'.\n";
    return 1;
  }
  else {
    ::printlog("Done.\n");
    print STDERR "Done.\n";
    return 0;
  }
}
# read users answer for a yes/no question. If user chose y return 1,
# if he chose n return 0
sub user_agrees {
  my $default=undef;
  if (@_){$default = shift;}
  $answer=<STDIN>;
  chomp($answer);
  if ($answer eq "" && defined($default)){$answer=$default;}
  ::printlog("$answer\n");
  while(($answer !~ /^[yY]$/) && ($answer !~ /^[nN]$/)) {
    ::printlog("'$answer' is not a valid answer.\nPlease enter 'y' or 'n': ");
    print STDERR "'$answer' is not a valid answer.\nPlease enter 'y' or 'n': ";
    $answer=<STDIN>;chomp($answer);
    ::printlog("$answer\n");
  }
  if ($answer =~ /^[nN]$/) {
    return 0;
  } # user doesn't agree

  return 1; # user agrees
}

# returns 1 if empty, 0 if not
sub is_dir_empty {
  my $dir = shift;
  @lines = `/bin/ls \"$dir\"`;
  if (@lines == 0) {
    return 1;
  }
  return 0;
}

