//
//  Database.m
//  ZXing
//
//  Created by Christian Brunschen on 29/05/2008.
/*
 * Copyright 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#import "Database.h"
#import "Scan.h"

@implementation Database

static sqlite3_stmt *maxIdStatement;
static sqlite3_stmt *selectAllStatement;
static sqlite3_stmt *insertStatement;
static sqlite3_stmt *deleteStatement;

@synthesize connection;
@synthesize nextScanIdent;

static Database *sharedDatabase = nil;

+ (id)sharedDatabase {
  if (!sharedDatabase) {
    sharedDatabase = [[self alloc] init];
    
    BOOL success;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"scans.db"];
    success = [fileManager fileExistsAtPath:writableDBPath];
    if (!success) {
      // The writable database does not exist, so copy the default to the appropriate location.
      NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"scans.db"];
      success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
      if (!success) {
        NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
      }
    }
    
    sqlite3 *connection;
    sqlite3_open([writableDBPath UTF8String], &connection);
    sharedDatabase.connection = connection;
    
    static const char *maxIdSql = "SELECT MAX(id) FROM SCAN";
    sqlite3_prepare_v2(connection, maxIdSql, -1, &maxIdStatement, NULL);
    
    static const char *selectAllSql = "SELECT id, text, stamp FROM SCAN ORDER BY id";
    sqlite3_prepare_v2(connection, selectAllSql, -1, &selectAllStatement, NULL);
    
    static const char *insertSql = 
      "INSERT INTO SCAN (id, text, stamp) VALUES (?, ?, ?)";
    sqlite3_prepare_v2(connection, insertSql, -1, &insertStatement, NULL);
    
    static const char *deleteSql = "DELETE FROM SCAN WHERE id = ?";
    sqlite3_prepare_v2(connection, deleteSql, -1, &deleteStatement, NULL);
    
    if (SQLITE_ROW == sqlite3_step(maxIdStatement)) {
      int maxId = sqlite3_column_int(maxIdStatement, 0);
      sharedDatabase.nextScanIdent = maxId + 1;
      sqlite3_reset(maxIdStatement);
    } else {
      NSLog(@"failed to read max ID from database\n");
    }
    
  }
  return sharedDatabase;
}

- (void)addScanWithText:(NSString *)text {
  sqlite3_bind_int(insertStatement, 1, nextScanIdent++);
  sqlite3_bind_text(insertStatement, 2, [text UTF8String], -1, SQLITE_TRANSIENT);
  sqlite3_bind_double(insertStatement, 3, [[NSDate date] timeIntervalSince1970]);
  sqlite3_step(insertStatement);
  sqlite3_reset(insertStatement);
}

- (NSArray *)scans {
  NSMutableArray *scans = [NSMutableArray array];
  while (SQLITE_ROW == sqlite3_step(selectAllStatement)) {
    int ident = sqlite3_column_int(selectAllStatement, 0);
    NSString *text = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectAllStatement, 1)];
    NSDate *stamp = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_double(selectAllStatement, 2)];
    Scan *scan = [[Scan alloc] initWithIdent:ident text:text stamp:stamp];
    [scans addObject:scan];
    [scan release];
  }
  sqlite3_reset(selectAllStatement);
  return scans;
}

- (void)deleteScan:(Scan *)scan {
  sqlite3_bind_int(deleteStatement, 1, [scan ident]);
  sqlite3_step(deleteStatement);
  sqlite3_reset(deleteStatement);
}


@end
