#  Copyright (c) 1997-2021
#  Ewgenij Gawrilow, Michael Joswig, and the polymake team
#  Technische Universität Berlin, Germany
#  https://polymake.org
#
#  This program 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 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  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.
#-------------------------------------------------------------------------------
#
#  This file is part of the polymake database interface polyDB.
#
#   @author Silke Horn, Andreas Paffenholz
#   http://www.mathematik.tu-darmstadt.de/~paffenholz
#

package PolyDB::Collection;

# @category Database Collection Administration
# Common options for writing collection info and schema
options %common_options = (
   # String section collection name
   collection => $PolyDB::default::db_collection_name,
   # Bool update default false
   update => false,
   # Bool verbose default false
   verbose => false,
   # Bool replace default false
   replace => false
);

# @category Database Collection Administration
# Options for writing collection info
options %info_options = (
   %common_options,
   # String schema_id id of the associated schema doc
   schema_id => undef, 
);

# @category Database Collection Administration
# Options for writing collection schema
options %schema_options = (
   %common_options,
   # String schema_id id 
   schema_id => undef, 
);

# @category Database Collection Administration
# set the info for a new collection
# @param HASH info the info document
# @options %info_options
user_method set_info ($;%info_options) {
   my ($self, $info, $options) = @_;

   my $version = $PolyDB::default::db_polydb_version;
   $info->{_id} = "info.".$version;

   my $info_col = $self->get_own_info_collection();

   if ( defined($options->{schema_id}) ) {
      $info->{schema} = $options->{schema_id};
   }
   die "schema_id must be given in info file or as an option\n" if !defined($info->{schema});
   
   my $res=$info_col->find_one({'_id' => $info->{schema} });
   die "no schema with id ".$info->{schema}." found. Please insert schema first\n" if !defined($res);

   if ( $options->{replace} ) { $options->{update} = true; }
   $res = $info_col->find_one({'_id' => $info->{_id} });
   die "info already exists but none of the options update or replace is given\n" if (defined($res) && !$options->{update});
   if ( !defined($res) ) { $options->{update} = false; }

   my $collection_name = $self->{name};
   (my $section_name, $info->{collection}) = $collection_name =~ /(.*)\.([\w-]+)/;
   @{$info->{section}} = split /\./, $section_name;   

   if ($options->{update}) {
      my $output;
      if ( $options->{replace} ) {
         $output = $info_col->replace_one({_id => $info->{_id}}, $info);
      } else {
         $output = $info_col->update_one({_id => $info->{_id}}, {'$set' => $info});
      }
      if ($options->{verbose}) {
         if ($output->acknowledged) {
            print "successfully updated type information for $section.$collection\n"
         } else {
            print "an error occurred when trying to update the type_information for $section.$collection:\n$output\n";
         }
      }

   } else {
      my $output = $info_col->insert_one($info);
      if ($options->{verbose}) {
         if ($output->acknowledged) {
            print "successfully saved type information for $section.$collection\n";
         } else {
            print "an error occurred when trying to save the type_information for $section.$collection:\n$output\n";
         }
      }
   }

}

# @category Database Collection Administration
# set the schema for a new collection
# @param HASH schema the schema document
# @options %schema_options
user_method set_schema ($; %schema_options) {
   my ($self, $schema, $options) = @_;

   my $version = $PolyDB::default::db_polydb_version;

   if ( ref($schema) eq "Polymake::Schema" ) {
      $schema = $schema->source;
   }

   my $info_col = $self->get_own_info_collection();
   my $schema_id = $options->{schema_id} // "schema.".$version;
   
   if ( $options->{replace} ) { $options->{update} = true; }
   my $res=$info_col->find_one({'_id' => $schema_id});
   die "schema already exists but none of the options update or replace is given\n" if (defined($res) && !$options->{update});
   if ( !defined($res) ) { $options->{update} = false; }

   my $collection_name = $self->{name};
   my ($section_name, $collection) = $collection_name =~ /(.*)\.([\w-]+)/;
   my $section_array =[];
   @$section_array = split /\./, $section_name;

   $schema = Schema::schema2document($schema);
   
   if ($options->{update}) {
      my $output = $info_col->update_one({_id => $schema_id}, {'$set' => { schema => $schema, section=>$section_array, collection=>$collection}});
      if ($options->{verbose}) {
         if ($output->acknowledged) {
            print "successfully updated schema for $self->{collection} with schema_id $schema_id\n"
         } else {
            print "an error occurred when trying to update the schema for $self->{collection} with schema_id $schema_id:\n$output\n";
         }
      }
   } else {
      my $output = $info_col->insert_one({ '_id' => $schema_id, schema => $schema, section=>$section_array, collection=>$collection });
      if ($options->{verbose}) {
         if ($output->acknowledged) {
            print "successfully saved schema for $self->{collection} with schema_id $schema_id\n";
         } else {
            print "an error occurred when trying to save the schema for $self->{collection} with schema_id $schema_id:\n$output\n";
         }
      }
   }
}

# @category Database Collection Administration
# list all indices defined for a collection
user_method indices () {
   my ($self) = @_;

   my $indexes = $self->indexes->list;
   while ( my $index = $indexes->next ) {
      print $index->{name}, "\n";
      foreach (keys %{$index->{key}} ) {
         print "   ", $_, ": ";
         print $index->{key}->{$_} == 1 ? "ascending" : "descending";
         print "\n";
      }
   }
}

# Local Variables:
# mode: perl
# cperl-indent-level:3
# indent-tabs-mode:nil
# End:
