# Agalma - Tools for processing gene sequence data and automating workflows
# Copyright (c) 2012-2017 Brown University. All rights reserved.
#
# This file is part of Agalma.
#
# Agalma 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 3 of the License, or
# (at your option) any later version.
#
# Agalma 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.
#
# You should have received a copy of the GNU General Public License
# along with Agalma.  If not, see <http://www.gnu.org/licenses/>.

"""
Provides an interface to the underlying SQLite database for all permanently
stored data generated by Agalma.
"""

import operator
import os
import re
from itertools import groupby, izip

from biolite import catalog
from biolite import config
from biolite import diagnostics
from biolite import utils
from biolite.database import execute, executemany, executescript, store, retrieve, execute_ramdisk, execute_dataframe, register_init


### MOLECULE TYPES ###

molecule_types = {
	"ribosomal-small": "S",
	"ribosomal-large": "L",
	"protein-coding": "P",
	"unknown": "-"}

re_ribosomal_small = re.compile(r"^small-\w+-rRNA")
re_ribosomal_large = re.compile(r"^large-\w+-rRNA")

def get_molecule_type(hit):
	"""
	Parse a BLAST hit to determine if the molecule type is small or large
	ribosomal.
	"""
	if re_ribosomal_small.match(hit):
		return molecule_types["ribosomal-small"]
	elif re_ribosomal_large.match(hit):
		return molecule_types["ribosomal-large"]
	else:
		return molecule_types["unknown"]


### GENOME TYPES ###

genome_types = {
	"mitochondrial": "M",
	"plastid": "P",
	"nuclear": "N",
	"vector": "V",
	"unknown": "-"}

def get_genome_type(hit):
	"""
	Parse a BLAST hit to determine the genome type of the sequence, either
	mitochondrial, plastid, or nuclear.
	"""
	if hit:
		og = hit.find("OG=")
		if og >= 0:
			if hit[og+3:].startswith("Mitochondrion"):
				return genome_types["mitochondrial"]
			elif hit[og+3:].startswith("Plastid"):
				return genome_types["plastid"]
			else:
				return genome_types["unknown"]
		elif hit.startswith("gnl|uv|"):
			return genome_types["vector"]
		else:
			return genome_types["nuclear"]
	else:
		return genome_types["unknown"]


### CDD DOMAINS ###

# List of domains to mask, should eventually be put in config file
domains_to_mask = [
'gnl|CDD|144943',
'gnl|CDD|201208',
'gnl|CDD|200957',
'gnl|CDD|197705',
'gnl|CDD|143167',
'gnl|CDD|200980',
'gnl|CDD|200936',
'gnl|CDD|144972',
'gnl|CDD|200951',
'gnl|CDD|206635',
'gnl|CDD|197520',
'gnl|CDD|143165',
'gnl|CDD|29261',
'gnl|CDD|200936',
'gnl|CDD|197603',
'gnl|CDD|201739',
'gnl|CDD|200931',
'gnl|CDD|200948',
'gnl|CDD|200998',
'gnl|CDD|201332',
'gnl|CDD|201372',
'gnl|CDD|201053',
'gnl|CDD|201004',
'gnl|CDD|201223',
'gnl|CDD|200988',
'gnl|CDD|200930',
'gnl|CDD|197585',
'gnl|CDD|197685',
'gnl|CDD|197533',
'gnl|CDD|28904',
'gnl|CDD|201276',
'gnl|CDD|28904',
'gnl|CDD|197562',
'gnl|CDD|28898',
'gnl|CDD|201143',
'gnl|CDD|197480'
]


"""
The domains to mask are specified via the PSSM-Id, but the list that we have
from previous analyses is of the "View PSSM" field. Can search for the "View
PSSM" field at

http://www.ncbi.nlm.nih.gov/Structure/cdd/cdd.shtml

Then get the PSSM-Id in the Statistics dropdown of the result page

"View PSSM"	"PSSM-Id"
pfam01535	144943
pfam00400	201208
pfam00047	200957
smart00407	197705
cd00099	143167
pfam00076	200980
pfam00023	200936
pfam01576	144972
pfam00041	200951
cd00031	206635
smart00112	197520
cd00096	143165
cd00204	29261
pfam00023	200936
smart00248	197603
pfam01344	201739
pfam00018	200931
pfam00038	200948
pfam00096	200998
pfam00595	201332
pfam00651	201372
pfam00169	201053
pfam00105	201004
pfam00435	201223
pfam00084	200988
pfam00017	200930
smart00225	197585
smart00367	197685
smart00135	197533
cd00020	28904
pfam00514	201276
cd00020	28904
smart00185	197562
cd00014	28898
pfam00307	201143
smart00033	197480
"""

def strip_stop_codons(seq, seq_type):
	"""
	"""
	# Trim any stop codons
	if seq and seq_type[0] == 'a':
		stopcodon = seq.find('*')
		if stopcodon >= 0:
			return seq[:stopcodon]
	return seq

### MODELS/GENES/SEQUENCES ###

models_schema = (
	("id", "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"),
	("run_id", "INTEGER"),				# Foreign key to runs table, refers to
										# the run_id of the process that
										# populates the database
	("catalog_id", "VARCHAR(255)"),		# Foreign key to catalog.id; could be
										# obtained through join with run table
										# but including it here makes things
										# more robust
	("confidence", "FLOAT"),
	("expression", "FLOAT"),
	("genome_type", "CHAR(1)"),			# Nuclear, mitochondrial, plastid
	("molecule_type", "CHAR(1)"),		# Protein coding, small/large ribosomal
	("blast_title", "TEXT"),			# The name, gi, and evalue of the top
	("blast_evalue", "FLOAT")			# blast hit; provides a human readable
										# label
)
models_index = ("run_id", "confidence")

genes_schema = (
	("run_id", "INTEGER"),
	("version", "INTEGER"),
	("model_id", "INTEGER"),
	("gene", "VARCHAR(255)"),
	("isoform", "INTEGER")
)
genes_index = ("run_id", "version", "model_id", "gene")

sequences_schema = (
	("run_id", "INTEGER"),
	("model_id", "INTEGER"),
	("type", "CHAR(1)"),		# a = aa, c = cds, n = nt
	("strand", "CHAR(1)"),		# ? = unknown, + = forward, - = reverse
	("header", "TEXT"),
	("sequence", "TEXT")
)
sequences_index = ("run_id", "model_id", "type", "strand")


def insert_models(run_id, id, seq_type, rows, strand='?', genome_type='-', molecule_type='-'):
	"""
	"""
	sql_models = """
		INSERT INTO agalma_models
		VALUES (NULL,%s,'%s',0,0,?,?,?,?);
		""" % (run_id, id)
	sql_genes = """
		INSERT INTO agalma_genes
		VALUES (%s,0,?,?,?);
		""" % run_id
	sql_sequences = """
		REPLACE INTO agalma_sequences
		VALUES (%s, ?,'%s','%s',?,?);
		""" % (run_id, seq_type, strand)
	execute("BEGIN DEFERRED")
	execute("DELETE FROM agalma_models WHERE run_id=?;", (run_id,))
	execute("DELETE FROM agalma_genes WHERE run_id=?;", (run_id,))
	for row in rows:
		model_id = execute(sql_models, (
						row.get("genome_type", genome_type),
						row.get("molecule_type", molecule_type),
						row.get("blast_title"),
						row.get("blast_evalue"))).lastrowid
		execute(sql_genes, (model_id, row["gene"], row["isoform"]))
		execute(sql_sequences, (model_id, row["header"], row["sequence"]))
	execute("COMMIT")


def update_models(rows, *columns):
	"""
	"""
	set_clause = ", ".join("%s=?" % column for column in columns)
	sql = "UPDATE agalma_models SET %s WHERE id=?;" % set_clause
	execute("BEGIN DEFERRED")
	executemany(sql, rows)
	execute("COMMIT")


def update_sequences(rows, run_id, seq_type):
	"""
	"""
	sql = "REPLACE INTO agalma_sequences VALUES (%s,?,'%s',?,?,?);" % (run_id, seq_type)
	execute("BEGIN DEFERRED")
	executemany(sql, rows)
	execute("COMMIT")


def max_genes_version(run_id):
	"""
	Returns the max (e.g. latest) value for `version` in the genes table for
	assembly `run_id`.
	"""
	return execute("SELECT MAX(version) FROM agalma_genes WHERE run_id=%s;" % run_id).fetchone()[0]


def latest_genes_version(id):
	"""
	Returns the `version` in genes table for the most recent run of treeinform
	for phylogeny `id`.
	"""
	try:
		version = diagnostics.lookup_prev_run(id, None, "treeinform").id
		utils.info("using genes version", version)
	except AttributeError:
		version = 0
		utils.info("using default genes version 0")
	return version


def select_genes(version=0):
	"""
	"""
	return execute("""
		SELECT run_id, model_id, gene, isoform
		FROM agalma_genes
		WHERE version=?;""", (version,))


def insert_genes(version, rows):
	"""
	"""
	assert version != "0"
	sql = """
		INSERT INTO agalma_genes (run_id, version, model_id, gene, isoform)
		VALUES (?, %d, ?, ?, ?);
		""" % int(version)
	execute("BEGIN DEFERRED")
	execute("DELETE FROM agalma_genes WHERE version=%d;" % int(version))
	executemany(sql, rows)
	execute("COMMIT")


def validate_genes(version, reassigned):
	"""
	"""

	def sql_compare(sql, a, b):
		A = execute(sql % a).fetchone()[0]
		B = execute(sql % b).fetchone()[0]
		return A, B

	# all model_id values are unique across the revised assembly
	result = sql_compare(
		"SELECT COUNT(%s) FROM agalma_genes WHERE version=%s;",
		("DISTINCT model_id", version), ("*", version))
	utils.info("""Validating model IDs:
		  unique model_id: %d
		=    all model_id: %d""" % result)
	if not (result[0] == result[1]):
		utils.die("validation failed!")

	# there are the same number of transcripts in the original assembly and the
	# revised assembly
	result = sql_compare(
		"SELECT COUNT(*) FROM agalma_genes WHERE version=%s;",
		0, version)
	utils.info("""Validating number of transcripts:
		  original assembly: %d
		=  revised assembly: %d""" % result)
	if not (result[0] == result[1]):
		utils.die("validation failed!")

	# the difference in number of genes between the original and revised
	# assembly should be equal to the number of reassigned genes
	a = execute("""
		SELECT COUNT(DISTINCT gene) FROM agalma_genes WHERE version=%s;
		""" % 0).fetchone()[0]
	b = execute("""
		SELECT COUNT(DISTINCT gene) FROM agalma_genes WHERE version=%s;
		""" % version).fetchone()[0]
	c = execute("""
		SELECT COUNT(DISTINCT gene) FROM agalma_genes
		WHERE version=%s AND gene LIKE 'REASSIGN.%%'
		""" % version).fetchone()[0]
	utils.info("""Validating number of genes:
		  original assembly: %d
		-        reassigned: %d
		+     newly created: %d
		=  revised assembly: %d""" % (a, reassigned, c, b))
	if not (a - reassigned + c == b):
		utils.die("validation failed!")


def export_exemplars(genes_version, outfile, seq_type='n', molecule_type=None, genome_type=None):
	"""
	Returns a list of (id, sequence) tuples corresponding to an exemplar for
	each gene in the specified genes `run_id`.

	`seq_type` selects the corresponding type in the sequences tables.

	By default, all genome and molecule types are selected, but this can be
	restricted using the optional keyword args.
	"""

	where = ["genes.version=?"]
	values = [genes_version]

	if molecule_type:
		where.append(
			"AND (%s)" % ' OR '.join(["models.molecule_type=?"]*len(molecule_type)))
		values += map(molecule_types.get, molecule_type)

	if genome_type:
		where.append(
			"AND (%s)" % ' OR '.join(["models.genome_type=?"]*len(genome_type)))
		values += map(genome_types.get, genome_type)

	sql = """
		SELECT
		  genes.model_id,
		  sequences.sequence,
		  genes.gene,
		  MAX(models.confidence)
		FROM
		  agalma_genes AS genes,
		  agalma_sequences AS sequences,
		  agalma_models AS models,
		  runs
		ON
		  genes.model_id=sequences.model_id AND
		  sequences.model_id=models.id AND
		  models.run_id=runs.id
		WHERE %s AND
		  sequences.type='%s' AND
		  models.confidence>=0 AND
		  runs.hidden=0
		GROUP BY genes.gene;""" % (' '.join(where), seq_type[0])

	n = 0
	with open(outfile, "w") as f:
		for row in execute(sql, values):
			seq = strip_stop_codons(row[1], seq_type)
			if seq:
				utils.write_fasta(f, seq, row[0])
				n += 1
			else:
				utils.info("missing %s sequence for %s" % (seq_type, row[0]))

	return n


def export_sequences(run_id, outfile, id_column="model_id", seq_type='n'):
	"""
	Write a FASTA file to `outfile` containing all the nucleotide sequences in
	the database for `run_id`.
	"""

	sql = """
		SELECT sequences.%s, sequences.sequence
		FROM agalma_sequences AS sequences JOIN agalma_models AS models
		ON sequences.model_id=models.id
		WHERE models.run_id=%s AND sequences.type='%s';""" % (id_column, run_id, seq_type)

	with open(outfile, "w") as f:
		for row in execute(sql):
			utils.write_fasta(f, strip_stop_codons(row[1], seq_type), row[0])


def export_gene_map(run_id, seqfile, mapfile, seq_type='n'):
	"""
	Write a tsv file linking genes to isoforms.
	"""

	version = max_genes_version(run_id)

	sql = """
		SELECT genes.model_id, genes.gene, sequences.sequence
		FROM agalma_genes AS genes JOIN agalma_sequences AS sequences
		ON genes.model_id=sequences.model_id
		WHERE genes.run_id=%s AND sequences.type='%s' AND genes.version=%d
		ORDER BY genes.model_id;""" % (run_id, seq_type, version)

	with open(seqfile, "w") as fseq, open(mapfile, "w") as fmap:
		for row in execute(sql):
			utils.write_fasta(fseq, strip_stop_codons(row[2], seq_type), row[0])
			fmap.write(row[1])
			fmap.write('\t')
			fmap.write(str(row[0]))
			fmap.write('\n')


def select_model_types(run_id):
	"""
	Returns a summary matrix of the number of genome vs. molecule types.
	"""
	sql = """
		SELECT genome_type, molecule_type
		FROM agalma_models
		WHERE run_id=%s;""" % run_id
	return execute_dataframe(sql)


def select_model_coverage(run_id):
	"""
	Return a pandas dataframe for the models in `run_id` with columns:
	
		expression, confidence, annotated
	"""
	sql = """
		SELECT expression, confidence, blast_title IS NOT NULL AS annotated
		FROM agalma_models
		WHERE run_id=%s;""" % run_id
	return execute_dataframe(sql)


### EXPRESSION ###

expression_schema = (
	("id", "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"),
	("run_id", "INTEGER"),				# Foreign key to runs table, refers to
										# the run_id of the process that
										# populates the database
	("reference_id", "INTEGER"),		# Foreign key to runs table, refers to
										# the run_id for the reference used
	("gene", "VARCHAR(256)"),
	("expression", "FLOAT")
)
expression_index = ("run_id", "reference_id", "gene")

def insert_expression(run_id, reference_id, rows):
	"""
	"""
	sql = """
		INSERT INTO agalma_expression
		VALUES (NULL,%s,%s,?,?);""" % (run_id, reference_id)
	execute("BEGIN DEFERRED")
	execute("DELETE FROM agalma_expression WHERE run_id=?;", (run_id,))
	executemany(sql, rows)
	execute("COMMIT")

def select_expression(run_id):
	"""
	"""
	return execute("""
		SELECT gene, expression
		FROM agalma_expression
		WHERE run_id=%d;""" % int(run_id))


### HOMOLOGY ###

homology_schema = (
	("id", "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"),
	("run_id", "INTEGER"),
	("parent_id", "INTEGER"),
	("size", "INTEGER")
)
homology_index = ("run_id", "parent_id", "size")

homology_models_schema = (
	("homology_id", "INTEGER"),	# The id assigned to the component during graph processing
	("model_id", "INTEGER")		# Foreign key to models table, identifies the sequence assigned to a particular component
)
homology_models_index = ("homology_id", "model_id")


def insert_homology(run_id, rows):
	"""
	"""
	execute("BEGIN DEFERRED")

	# Delete any leftover rows from a previous attempt with this run_id.
	execute("""
		DELETE FROM agalma_homology_models
		WHERE homology_id IN (
			SELECT id
			FROM agalma_homology
			WHERE run_id=%d
		);""" % int(run_id))
	execute("""
		DELETE FROM agalma_homology
		WHERE run_id=%d;""" % int(run_id))

	# Insert new rows, a cluster at a time.
	insert_sql = """
		INSERT INTO agalma_homology
		VALUES (NULL,%d,NULL,?);""" % int(run_id)
	insert_cluster_sql = """
		INSERT INTO agalma_homology_models
		VALUES (?,?);"""
	for cluster in rows:
		homology_id = execute(insert_sql, (len(cluster),)).lastrowid
		for sequence_id in cluster:
			execute(insert_cluster_sql, (homology_id, sequence_id))

	execute("COMMIT")


def insert_pruned_homology(run_id, rows):
	"""
	"""
	execute("BEGIN DEFERRED")

	# Delete any leftover rows from a previous attempt with this run_id.
	execute("""
		DELETE FROM agalma_homology_models
		WHERE homology_id IN (
			SELECT id
			FROM agalma_homology
			WHERE run_id=%d
		);""" % int(run_id))
	execute("""
		DELETE FROM agalma_homology
		WHERE run_id=%d;""" % int(run_id))

	# Insert new rows, a cluster at a time.
	insert_sql = """
		INSERT INTO agalma_homology
		VALUES (NULL,%d,?,?);""" % int(run_id)
	insert_cluster_sql = """
		INSERT INTO agalma_homology_models
		VALUES (?,?);"""
	for parent_id, cluster in rows:
		homology_id = execute(insert_sql, (parent_id, len(cluster))).lastrowid
		for sequence_id in cluster:
			execute(insert_cluster_sql, (homology_id, sequence_id))

	execute("COMMIT")


def select_species(genes_version):
	"""
	Returns a list of tuples with the following for each species in the genes
	table:

	run_id		The run id that populated the models for this species
	catalog_id	The agalma catalog id
	species		The species names
	ncbi_id		The NCBI taxon id
	itis_id		The ITIS taxon id

	"""
	sql = """
		SELECT DISTINCT genes.run_id, catalog.id, catalog.species, catalog.ncbi_id, catalog.itis_id
		FROM agalma_genes AS genes, runs, catalog
		ON genes.run_id=runs.id AND runs.catalog_id=catalog.id
		WHERE genes.version=? AND runs.hidden=0;"""
	return [tuple(row) for row in execute(sql, (genes_version,))]


def select_homology_models(run_id, seq_type, max_length):
	"""
	Returns an iterator through the clusters of homologous models from
	`run_id`.

	Each iteration yields a tuple with the component id and a list of
	(taxon, model_id, sequence) tuples in the component with
	sequences shorter than `max_length`.

	Aborts if any entry in the homology table joins to an empty sequence (for
	instance, if the requested `seq_type` isn't available for that sequence).
	"""

	# Load components from database

	taxa = {}

	homology_models_sql = """
		SELECT homology.id          AS homology_id,
		       models.catalog_id    AS catalog_id,
		       models.id            AS id,
		       sequences.sequence   AS sequence
		FROM agalma_homology        AS homology        JOIN
		     agalma_homology_models AS homology_models JOIN
		     agalma_models          AS models          JOIN
		     agalma_sequences       AS sequences
		     ON homology.id=homology_models.homology_id AND
		        homology_models.model_id=models.id AND
		        models.id=sequences.model_id
		WHERE homology.run_id=? AND sequences.type='%s'
		ORDER BY homology.id ASC;""" % seq_type

	if config.get_resource("ramdisk"):
		rows = execute_ramdisk(homology_models_sql, (run_id,))
	else:
		rows = execute(homology_models_sql, (run_id,))

	for homology_id, cluster in groupby(rows, operator.itemgetter(0)):
		sequences = []
		for row in cluster:
			if row["sequence"] is None:
				utils.die("empty sequence in record:", row)
			# Only accept sequences that are shorter than max_length
			if len(row["sequence"]) <= max_length:
				# Check if this catalog id has already been looked up
				if not row["catalog_id"] in taxa:
					# Lookup species names for catalog id
					record = catalog.select(row["catalog_id"])
					if not record or not record.species:
						utils.die("couldn't find species for catalog id '%s'" % row["catalog_id"])
					taxa[row["catalog_id"]] = utils.safe_taxon(record.species)
			sequences.append((
					taxa[row["catalog_id"]],
					row["id"],
					strip_stop_codons(row["sequence"], seq_type)))
		yield homology_id, sequences

	utils.info(
		"found the following taxa for homology id %d:\n" % run_id,
		'\n '.join("%s (%s)" % (taxon, id) for id, taxon in taxa.iteritems()))

	diagnostics.log("taxa", str(taxa))


def count_homology(run_id):
	"""
	"""
	sql = """
		SELECT size, COUNT(*)
		FROM agalma_homology
		WHERE run_id=?
		GROUP BY size
		ORDER BY size ASC;"""
	return map(tuple, execute(sql, (run_id,)))


### ALIGNMENTS ###

alignments_schema = (
	('id', 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'),
	('run_id', 'INTEGER'),			# Foreign key to runs table, refers to the run_id of the process that assigned homology and populated this table
	('homology_id', 'INTEGER'),			# Foreign key to homology table, refers to the id of the homologous cluster this alignment belongs to
	('alignment', 'TEXT')			# Nucleotide or amino acid multiple alignment in FASTA format
)
alignments_index = ('run_id', 'homology_id')


def insert_alignments(run_id, rows):
	"""
	"""
	execute("BEGIN DEFERRED")

	# Delete any leftover rows from a previous attempt with this run_id.
	execute("""
		DELETE FROM agalma_alignments
		WHERE run_id=%d;""" % int(run_id))

	# Insert new rows.
	sql = """
		INSERT INTO agalma_alignments
		VALUES (NULL,%d,?,?);""" % int(run_id)
	executemany(sql, rows)

	execute("COMMIT")


def select_alignments(run_id):
	"""
	"""
	return execute("""
		SELECT id, alignment
		FROM agalma_alignments
		WHERE run_id=%d;""" % int(run_id))


### TREES ###

trees_schema = (
	("id", "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"),
	("run_id", "INTEGER"),			# Foreign key to runs table
	("alignment_id", "INTEGER"),			# Foreign key to alignment table
	("tree", "TEXT")			# Tree in newick format
)
trees_index = ("run_id", "alignment_id")


def insert_trees(run_id, rows):
	"""
	"""
	execute("BEGIN DEFERRED")

	# Delete any leftover rows from a previous attempt with this run_id.
	execute("""
		DELETE FROM agalma_trees
		WHERE run_id=%d;""" % int(run_id))

	# Insert new rows.
	sql = """
		INSERT INTO agalma_trees
		VALUES (NULL,%d,?,?);""" % int(run_id)
	executemany(sql, rows)

	execute("COMMIT")


def select_trees(run_id):
	"""
	"""
	return execute("""
		SELECT id, tree
		FROM agalma_trees
		WHERE run_id=%d;""" % int(run_id))


### INIT ###

def _create_sql(name, schema, index):
	sql = [" CREATE TABLE IF NOT EXISTS %s (" % name]
	sql += ["   %s %s," % s for s in schema[:-1]]
	sql += ["   %s %s);" % schema[-1]]
	sql += [" CREATE INDEX IF NOT EXISTS {0}_{1} ON {0}({1});".format(name, i) for i in index]
	return '\n'.join(sql)

models_sql = _create_sql("agalma_models", models_schema, models_index)
genes_sql = _create_sql("agalma_genes", genes_schema, genes_index)
sequences_sql = _create_sql("agalma_sequences", sequences_schema, sequences_index)
sequences_sql += " CREATE UNIQUE INDEX IF NOT EXISTS agalma_sequences_model_id_type ON agalma_sequences(model_id,type);"
expression_sql = _create_sql("agalma_expression", expression_schema, expression_index)
homology_sql = _create_sql("agalma_homology", homology_schema, homology_index)
homology_models_sql = _create_sql("agalma_homology_models", homology_models_schema, homology_models_index)
alignments_sql = _create_sql("agalma_alignments", alignments_schema, alignments_index)
trees_sql = _create_sql("agalma_trees", trees_schema, trees_index)

def init():
	# Performance tuning recommended by:
	# http://stackoverflow.com/questions/784173
	pragma = """
		PRAGMA main.page_size=65536;
		PRAGMA main.cache_size=4096;
		PRAGMA main.cache_spill=0;
		PRAGMA main.locking_mode=NORMAL;
		PRAGMA main.synchronous=NORMAL;
		PRAGMA main.journal_mode=WAL;
		PRAGMA main.temp_store=MEMORY;"""
	executescript(pragma)
	executescript(
			models_sql +
			genes_sql +
			sequences_sql +
			expression_sql +
			homology_sql +
			homology_models_sql +
			alignments_sql +
			trees_sql)

register_init(init)


# vim: noexpandtab ts=4 sw=4
