#!/usr/bin/ruby

require 'odbc'
require 'csv'

$dsn = ARGV.shift
$uid = ARGV.shift
$pwd = ARGV.shift

@conn = ODBC.connect($dsn, $uid, $pwd)

def recreate(name, query)
    begin
        @conn.do("DROP TABLE " + name)
    rescue
        # Ignore errors on DROP TABLE
    end
    @conn.do(query)
end

def recreateV3Tables
    recreate('repinfo', <<-EOT)
    CREATE TABLE repinfo (
       id           SMALLINT PRIMARY KEY,
       memo         VARCHAR(30) NOT NULL,
       description  VARCHAR(255) NOT NULL,
       prio         INTEGER NOT NULL,
       descriptor   CHAR(6) NOT NULL,
       tablea       INTEGER NOT NULL,
       INDEX (prio),
       UNIQUE INDEX (memo)
    ) TYPE=InnoDB;
    EOT
    recreate('pseudoana', <<-EOT)
    CREATE TABLE pseudoana (
       id         INTEGER auto_increment PRIMARY KEY,
       lat        INTEGER NOT NULL,
       lon        INTEGER NOT NULL,
       ident      CHAR(64),
       UNIQUE INDEX(lat, lon, ident(8)),
       INDEX(lon)
    ) TYPE=InnoDB;
    EOT
    recreate('context', <<-EOT)
    CREATE TABLE context (
       id          INTEGER auto_increment PRIMARY KEY,
       id_ana      INTEGER NOT NULL,
       id_report   SMALLINT NOT NULL,
       datetime    DATETIME NOT NULL,
       ltype       SMALLINT NOT NULL,
       l1          INTEGER NOT NULL,
       l2          INTEGER NOT NULL,
       ptype       SMALLINT NOT NULL,
       p1          INTEGER NOT NULL,
       p2          INTEGER NOT NULL,
       UNIQUE INDEX (id_ana, datetime, ltype, l1, l2, ptype, p1, p2, id_report),
       INDEX (id_ana),
       INDEX (id_report),
       INDEX (datetime),
       INDEX (ltype, l1, l2),
       INDEX (ptype, p1, p2)
    ) TYPE=InnoDB;
    EOT
    recreate('data', <<-EOT)
    CREATE TABLE data (
       id_context  INTEGER NOT NULL,
       id_var      SMALLINT NOT NULL,
       value       VARCHAR(255) NOT NULL,
       INDEX (id_context),
       UNIQUE INDEX(id_var, id_context)
    ) TYPE=InnoDB;
    EOT
    recreate('attr', <<-EOT)
    CREATE TABLE attr (
       id_context  INTEGER NOT NULL,
       id_var      SMALLINT NOT NULL,
       type        SMALLINT NOT NULL,
       value       VARCHAR(255) NOT NULL,
       INDEX (id_context, id_var),
       UNIQUE INDEX (id_context, id_var, type)
    ) TYPE=InnoDB;
    EOT
end

@lastid = @conn.proc("SELECT LAST_INSERT_ID()") { |stmt|
	row = stmt.fetch
	row == nil ? nil : row[0].to_i
}
@getana = @conn.proc("SELECT id FROM pseudoana WHERE lat=? AND lon=? AND ident=?") { |stmt|
	row = stmt.fetch
	row == nil ? nil : row[0].to_i
}
@getananull = @conn.proc("SELECT id FROM pseudoana WHERE lat=? AND lon=? AND ident IS NULL") { |stmt|
    row = stmt.fetch
    row == nil ? nil : row[0].to_i
}
@newana = @conn.proc("INSERT INTO pseudoana (lat, lon, ident) VALUES (?, ?, ?)") { |stmt|
	stmt.nrows
}
@getctx = @conn.proc("SELECT id FROM context WHERE id_ana=? AND datetime=? AND ltype=? AND l1=? AND l2=? AND ptype=? AND p1=? AND p2=? AND id_report=?") { |stmt|
	row = stmt.fetch
	row == nil ? nil : row[0].to_i
}
@newctx = @conn.proc("INSERT INTO context (id_ana, datetime, ltype, l1, l2, ptype, p1, p2, id_report) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)") { |stmt|
	stmt.nrows
}
getri = @conn.proc("SELECT id FROM repinfo WHERE id = ?") { |stmt|
	row = stmt.fetch
	row == nil ? nil : row[0].to_i
}
newri = @conn.proc("INSERT INTO repinfo (id, memo, description, prio, descriptor, tablea) VALUES (?, ?, ?, ?, ?, ?)") { |stmt| stmt.nrows }
replaceri = @conn.proc("UPDATE repinfo SET memo=?, description=?, prio=?, descriptor=?, tablea=? WHERE id=?") { |stmt| stmt.nrows }
newdata = @conn.proc("INSERT INTO data (id_context, id_var, value) VALUES (?, ?, ?)") { |stmt| stmt.nrows }
newattr = @conn.proc("INSERT INTO attr (id_context, id_var, type, value) VALUES (?, ?, ?, ?)") { |stmt| stmt.nrows }


def obtainAna(lat, lon, ident)
	if ident
		id = @getana.call(lat, lon, ident)
	else
		id = @getananull.call(lat, lon)
	end
	if id == nil
		@newana.call(lat, lon, ident)
		return @lastid.call()
	end
	return id
end

def obtainContext(pa, dt, lt, l1, l2, pt, p1, p2, rep)
	dt.gsub!(/.+?(\d+-\d+-\d+ \d+:\d+:\d+).+/, '\1');
	id = @getctx.call(pa, dt, lt, l1, l2, pt, p1, p2, rep)
	if id == nil
		@newctx.call(pa, dt, lt, l1, l2, pt, p1, p2, rep)
		return @lastid.call()
	end
	return id
end

begin
	# Recreate the database tables with the v4 structure
	recreateV3Tables

	context_id = nil
	var_id = nil

	$stdin.each { |line|
		row = CSV.parse_line(line)
		if row[0] == 'R'
			# Repinfo
			id = row[1].to_i
			if getri.call(id)
			    replaceri.call(*(row[2..6] + [id]))
			else
			    # Work around a bug of old repinfo.csv that created repinfo
			    # tables with conflicting memo entries
			    if not (id == 105 and row[2] == 'ana')
				newri.call(id, *row[2..6])
			    end
			end
		elsif row[0] == 'D'
			# Data

			#  4 c.datetime,
			#  5 c.ltype,
			#  6 c.l1,
			#  7 c.l2,
			#  8 c.ptype,
			#  9 c.p1,
			# 10 c.p2,
			# 11 c.id_report,
			# 12 d.id_var,
			# 13 d.value

			ana_id = obtainAna(row[1].to_i, row[2].to_i, row[3])
			context_id = obtainContext(ana_id, *row[4..11])
			var_id = row[12].to_i
			newdata.call(context_id, var_id, row[13])
		elsif row[0] == 'A'
			# Attributes
			type, value = row[0].to_i, row[1]
			newattr.call(context_id, var_id, type, value)
		else
			$stderr.puts "Unknown line type: #{row[0]} at line #{$.}"
		end
	}
ensure
	getri.statement.drop
	replaceri.statement.drop
	newri.statement.drop
	@lastid.statement.drop
	@getana.statement.drop
	@getananull.statement.drop
	@newana.statement.drop
	@getctx.statement.drop
	@newctx.statement.drop
	newdata.statement.drop
	newattr.statement.drop
end

# vim:set ts=4 sw=4:
