#!/usr/bin/perl -w

use DBI;
use strict;

# Prácticas de DBI y bases de datos biológicas
# Script de inserción de entradas en formato SWISSPROT en la base de datos

my($dbhost)='localhost';
my($dbname)='masterdb';	# Teneis que introducir el nombre de la base de datos
				# que os corresponda
my($dbuser)='masteruser';	# Teneis que poner el nombre que os dé
my($dbpass)='masterpass';	# Teneis que poner la password que os dé

# Comprobación del número de parámetros
if(scalar(@ARGV)>0) {
	local(*INFILE);
	my($file,$line);
	my($errflag,$dbh);
	
	my(@acc,$id,$lastdate,$description,$sequence,$molw,$accnumber);
	my($readingseq);
	
	my($sthsw,$sthacc);
	
	# Apertura de la conexión con la base de datos
	# Establecemos que nosotros manejamos los errores,
	# y que vamos a trabajar con transacciones directamente
	$dbh = DBI->connect("dbi:Pg:dbname=$dbname;host=$dbhost",
				$dbuser,$dbpass,{RaiseError => 0, AutoCommit => 0});
	
	# ¿Se ha podido establecer la conexión?
	die "Ha habido un problema al conectar con la base de datos: " . $DBI::errstr  unless(defined($dbh));
	
	# Preparación de las operaciones de inserción a realizar repetidamente
	# (Debería hacer un chequeo aquí, para comprobar que funcionan)
	$sthsw=$dbh->prepare('INSERT INTO SWISSENTRY VALUES (?,?,?,?,?,?)');
	$sthacc=$dbh->prepare('INSERT INTO ACCNUMBERS(main_accnumber,accnumber) VALUES (?,?)');
	
	# Procesamiento de cada fichero
	foreach $file (@ARGV) {
		# Intento de abrir el fichero
		if(open(INFILE,$file)) {
			print "Procesando fichero $file\n";
			
			# Por seguridad, limpio las variables
			@acc=();
			$id='';
			$lastdate='';
			$description='';
			$sequence='';
			$molw='';
			$readingseq=undef;
			
			# Procesamiento del fichero, leyendo línea a línea
			while($line=<INFILE>) {
				# Lo primero, quitar el salto de línea
				chomp($line);
				
				# Detección del final del registro
				if($line =~ /^\/\//) {
					# Cuando se ha terminado de leer un
					# registro hay que proceder a guardar
					# los datos en la base de datos
					
					$description=undef  if($description eq '');
					
					# Impresión de comprobación
					print "ACC: $acc[0] ; ID: $id ; Last: $lastdate\n";
					
					# Ejecuto el resto de inserciones cuando no hay error
					if($sthsw->execute($acc[0],$id,$lastdate,$description,$sequence,$molw)) {
						foreach $accnumber (@acc) {
							unless($sthacc->execute($acc[0],$accnumber)) {
								# Ha ocurrido un error de inserción
								$errflag=1;
								last;
							}
						}
					} else {
						# Marco el error si se produce
						$errflag=1  
					}
					
					# ¿Se han podido realizar las inserciones?
					if(defined($errflag)) {
						warn "Error al insertar: " . $DBI::errstr;
						$dbh->rollback();
						# No voy a seguir procesando el fichero
						last;
					} else {
						# Una vez guardados los datos, tenemos
						# que borrar el contenido de las variables
						# para evitar fallos en las iteraciones
						@acc=();
						$id='';
						$lastdate='';
						$description='';
						$sequence='';
						$molw='';
						$readingseq=undef;
					}
					
					next;
				}
				
				# ¿Estoy leyendo una secuencia?
				if(defined($readingseq)) {
					# Quito todos los espacios intermedios 
					$line =~ s/\s+//g;
					
					# Y concateno
					$sequence .= $line;
					
				# Como no la estoy leyendo, busco los patrones apropiados
				} elsif($line =~ /^SQ.+(\d+) MW/) {
					# Extracción del peso molecular
					# y comienzo de secuencia
					$molw=$1;
					
					$readingseq=1;
				
				} elsif($line =~ /^ID   ([a-zA-Z0-9_]+)/) {
					# Identificador
					$id = $1;
				} elsif($line =~ /^DT   (\d{2}-[A-Z]{3}-\d{4}).+annotation update/) {
					# Fecha de la última actualización
					$lastdate = $1;
				} elsif($line =~ /^AC   (.+)/) {
					# Los accnumber, que pueden estar en varias líneas
					
					# Elimino los espacios
					my($x)=$1;
					$x =~ s/\s+//g;
					
					# Rompo por los puntos y coma, y
					# añado a la lista de accnumber
					push(@acc,split(/;/,$x));
				} elsif($line =~ /^DE   (.+)/) {
					# La descripción, que puede estar en varias líneas
					
					$description .= ' '  if($description ne '');
					$description .= $1;
				}
			}
			
			# Queremos que las inserciones se hagan efectivas
			# pero sólo se debe hacer cuando no se ha producido un error
			$dbh->commit()  unless(defined($errflag));
			
			# Se cierra el fichero procesado
			close(INFILE);
		} else {
			warn "Imposible abrir el fichero $file.";
		}
		
		# Detección de error al insertar, para no seguir procesando archivos
		last  if(defined($errflag));
	}
	
	# Por último, se cierra la conexión a la base de datos
	$dbh->disconnect();
} else {
	die "Debes introducir al menos un parámetro.";
}
