func DB.Open()
{
    var path = DB.working / "data.db";
    return Sqlite.Open(path);
}

func DB.CreateCSRF(ctx)
{
    var session = DB.GetSession(ctx);
    if(session)
    {
        var csrf = Crypto.Base64Encode(Crypto.RandomBytes(32, "CPKG"));


        var expires = DateTime.NowEpoch + 600;
        DB.Lock();
        DB.csrf.Add({
            Token = csrf,
            Expires = expires,
            Session = session
        });
        DB.Unlock();
        return csrf;
    }
    return "";
}

func DB.VerifyCSRF(session,csrf)
{
    if(TypeOf(csrf) != "String") return false;
    if(csrf.Length == 0) return false;
    csrf = csrf.Replace("\n","").Replace("\r","\n").Replace(" ","");
    if(csrf.Length == 0) return false;
    
    var retVal = false;
    var time = DateTime.NowEpoch;
    DB.Lock();
    var _oldCSRF = DB.csrf;
    DB.csrf = [];
    //This will be inefficient but hopefully there won't be too many csrf tokens at any given time (we try to delete the expired ones)
    each(var csrfItem : _oldCSRF)
    {
        if(time >= csrfItem.Expires) continue;
        if(csrfItem.Token == csrf && time < csrfItem.Expires && session == csrfItem.Session)
        {
            retVal=true;
            continue;
        }
        DB.csrf.Add(csrfItem);
    }
    DB.Unlock();
    return retVal;
}


func DB.Lock()
{
    DB.mtx.Lock();
}

func DB.Unlock()
{
    DB.mtx.Unlock();
}

func DB.GetUniqueNumber()
{
    DB.Lock();
    var unum = DB.u_n_counter++;
    DB.Unlock();
    return unum;
}

func DB.getPort()
{
    if(TypeOf(DB.Config.Port) == "Long") return DB.Config.Port;
    return 4206;
}

func DB.Init(working)
{
    DB.working = Path.FromString(working);
    DB.csrf = [];
    DB.u_n_counter=0;
    FS.Local.CreateDirectory(DB.working);
    FS.Local.CreateDirectory(DB.working / "Temp");
    FS.Local.CreateDirectory(DB.working / "Packages");

    each(var f : FS.Local.EnumeratePaths(DB.working / "Temp"))
    {
        if(FS.Local.FileExists(f)) FS.Local.DeleteFile(f);
    }

    DB.mtx = new Mutex();
    var p = DB.working / "conf.json";
    if(FS.Local.FileExists(p))
        DB.Config = Json.Decode(FS.ReadAllText(FS.Local, p));
    else
        DB.Config = {
            AllowRegister=false,
        };

    if(TypeOf(DB.Config) != "Dictionary") DB.Config = {AllowRegister=false};
    
    var dbCon = DB.Open();
    Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS packages (id INTEGER PRIMARY KEY AUTOINCREMENT, packageName TEXT UNIQUE, accountId INTEGER);");
    Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS versions (id INTEGER PRIMARY KEY AUTOINCREMENT, packageId INTEGER, version INTEGER, description TEXT, type TEXT, maintainer TEXT, homepage TEXT, repo TEXT, license TEXT, uploadTime INTEGER, pluginHost TEXT);");
    Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE, accountName TEXT UNIQUE, password_hash TEXT, password_salt TEXT, motto TEXT, verifyKey TEXT UNIQUE, verifyExpire INTEGER, flags INTEGER, created INTEGER, verified INTEGER);");
    Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS sessions (id INTEGER PRIMARY KEY AUTOINCREMENT, accountId INTEGER, key STRING UNIQUE, expires INTEGER, created INTEGER, name TEXT);");
    Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS reserved_prefixes (id INTEGER PRIMARY KEY AUTOINCREMENT, accountId INTEGER, prefix STRING UNIQUE);");
    Sqlite.Close(dbCon);
}

DB.FLAG_ADMIN = 0b00000010;
DB.FLAG_VERIFIED = 0b00000001;

DB.FLAG_RESETPASS = 0b00001000;
DB.FLAG_VERIFY = 0b00000100;

DB.ITTR = 35000;

DB.Expires = 86400*7;


