//
//  BaseDao.m
//  TaiZhouTobacco_7s
//
//  Created by JianjiYuan on 14-5-22.
//  Copyright (c) 2014年 JianjiYuan. All rights reserved.
//

#import "BaseDao.h"
#import "NSObject+Customized.h"

@implementation BaseDao

+ (instancetype)getInstance
{
    static BaseDao *instance = nil;
    @synchronized (self){
        static dispatch_once_t predicate;
        dispatch_once(&predicate, ^{
            instance = [[BaseDao alloc] init];
        });
        return instance;
    }
}

- (NSArray *)excuteSelectBySQL:(NSString *)sql
{
    FMDatabase *db = [DBInstance getInstance].db;
    
    [db open];
    NSArray *arrResults = nil;
    @try {
        [db beginDeferredTransaction];
        arrResults = [self selectDatasWithSql:sql];
    }
    @catch (NSException *exception) {
        DLog(@"%@", [exception reason]);
    }
    @finally {
        [db close];
    }
    if (arrResults && arrResults.count > 0) {
        return arrResults;
    }
    return @[];
}

- (BOOL)excuteSQL:(NSString *)sql operateType:(DaoOperateType)type
{
    FMDatabase *db = [DBInstance getInstance].db;
    
    [db open];
    BOOL result = YES;
    @try {
        [db beginDeferredTransaction];
        switch (type) {
            case DaoOperateTypeDelete:
            case DaoOperateTypeInsert:
                result = result && [db executeStatements:sql];
                break;
            case DaoOperateTypeUpdate:
                result = result && [db executeUpdate:sql];
                break;
            default:
                result = NO;
                break;
        }
        
    }
    @catch (NSException *exception) {
        DLog(@"%@", [exception reason]);
    }
    @finally {
        result = result?[db commit]:[db rollback];
        [db close];
    }
    return result;
}

- (BOOL)excuteSQLs:(NSArray *)sqls operateType:(DaoOperateType)type
{
    FMDatabase *db = [DBInstance getInstance].db;
    
    [db open];
    BOOL result = YES;
    @try {
        [db beginDeferredTransaction];
        switch (type) {
            case DaoOperateTypeDelete:
            case DaoOperateTypeInsert:
                for (NSString *sql in sqls) {
                    result = result && [db executeStatements:sql];
                }
                break;
            case DaoOperateTypeUpdate:
                for (NSString *sql in sqls) {
                    result = result && [db executeUpdate:sql];
                }
                break;
            default:
                result = NO;
                break;
        }
        
    }
    @catch (NSException *exception) {
        DLog(@"%@", [exception reason]);
    }
    @finally {
        result = result?[db commit]:[db rollback];
        [db close];
    }
    return result;
}

- (NSArray *)selectDatasWithSql:(NSString *)sql
{
    FMResultSet *resultSet = [[DBInstance getInstance].db executeQuery:sql];
    sqlite3_stmt *statement = resultSet.statement.statement;
    NSMutableArray *arrResults = [NSMutableArray array];
    
    while ([resultSet next]) {
        
        NSMutableDictionary *dictRow = [NSMutableDictionary dictionary];
        int columnCount = sqlite3_column_count(statement);
        for (int i = 0; i < columnCount; i++) {
            const char *name = sqlite3_column_name(statement, i);
            NSString *columnName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
            int type = sqlite3_column_type(statement, i);
            
            switch (type) {
                case SQLITE_INTEGER:
                {
                    int64_t value = sqlite3_column_int64(statement, i);
                    [dictRow setObject:[NSString stringWithFormat:@"%lld", value] forKey:columnName];
                }
                    break;
                case SQLITE_FLOAT:
                {
                    float value = sqlite3_column_double(statement, i);
                    [dictRow setObject:[NSNumber numberWithFloat:value] forKey:columnName];
                }
                    break;
                case SQLITE_TEXT:
                {
                    const char *value = (const char*)sqlite3_column_text(statement, i);
                    NSString *strTemp = [NSString stringWithCString:value encoding:NSUTF8StringEncoding];
                    if (strTemp.length > 0) {
                        if([strTemp isEqualToString:@"(null)"] || [strTemp isEqualToString:@"(NULL)"])
                            strTemp = @"";
                         strTemp = [strTemp stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                    }else {
                        strTemp = @"";
                    }
                    [dictRow setObject:strTemp forKey:columnName];
                }
                    break;
                case SQLITE_BLOB:
                {
                    
                }
                    break;
                case SQLITE_NULL:
                {
                    [dictRow setObject:@"" forKey:columnName];
                }
                    break;
                default:
                {
                    const char *value = (const char *)sqlite3_column_text(statement, i);
                    [dictRow setObject:[NSString stringWithCString:value encoding:NSUTF8StringEncoding] forKey:columnName];
                }
                    break;
            }
            
        }
        
        [arrResults addObject:dictRow];
        
    }
    return arrResults;
}

//INSERT
- (BOOL)insertData:(NSObject *)entity key:(NSString *)key toTable:(NSString *)table
{
    NSString *selectSql = [NSString stringWithFormat:@"SELECT COUNT(*) FROM %@ WHERE %@ == '%@';",
                           table ,key, [entity valueForKey:key]];
    NSArray *arrResults = [self excuteSelectBySQL:selectSql];
    if (arrResults.count > 0) {
        return NO;
    }
    NSString *sql = [self createInsertSql:entity toTable:table];
    return [self excuteSQL:sql operateType:DaoOperateTypeInsert];
}

- (BOOL)insertDatas:(NSArray *)entities key:(NSString *)key toTable:(NSString *)table
{
    NSMutableArray *sqls = [NSMutableArray array];
    for (NSObject *entity in entities) {
        
        NSString *selectSql = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ == '%@';",table ,key, [entity valueForKey:key]];
        NSArray *arrResults = [self excuteSelectBySQL:selectSql];
        if (arrResults.count > 0) {
            continue;
        }
        NSString *sql = [self createInsertSql:entity toTable:table];
        [sqls addObject:sql];
    }
    return [self excuteSQLs:sqls operateType:DaoOperateTypeInsert];
}

- (NSString *)createInsertSql:(NSObject *)entity toTable:(NSString *)table
{
    NSArray *properties = [entity getPropertyList];
    NSMutableString *sql = [[NSMutableString alloc] init];
    [sql appendFormat:@"insert into %@ (",table] ;
    NSInteger i = 0;
    for (NSString *key in properties) {
        if (i>0) {
            [sql appendString:@","];
        }
        [sql appendFormat:@"%@",key];
        i++;
    }
    [sql appendString:@") values ("];
    
    i = 0;
    for (NSString *key in properties) {
        NSString *value = nil;
        id valueObject = [entity valueForKey:key];
        
        if ([valueObject isKindOfClass:[NSArray class]]) {
            NSMutableString *strTemp = [NSMutableString string];
            BOOL isFirstItem = YES;
            for (NSString *strItem in (NSArray *)valueObject) {
                if (isFirstItem) {
                    [strTemp appendString:strItem];
                }else {
                    [strTemp appendFormat:@",%@", strItem];
                }
                isFirstItem = NO;
            }
            value = strTemp;
            
        }else {
            value = (NSString *)valueObject;
        }
        
        if (i>0) {
            [sql appendString:@","];
        }
        [sql appendFormat:@"'%@'", value];
        i++;
    }
    [sql appendString:@")"];
    
    DLog(@"createInsertSql  %@, entity %@", sql, entity);
    
    return sql;
}

//UPDATE
- (BOOL)updateData:(NSObject *)entity key:(NSString *)key inTable:(NSString *)table
{
    NSString *sql = [self createUpdateSql:entity key:key inTable:table];
    return [self excuteSQL:sql operateType:DaoOperateTypeUpdate];
}

- (BOOL)updateDatas:(NSArray *)entities key:(NSString *)key inTable:(NSString *)table
{
    NSMutableArray *sqls = [NSMutableArray array];
    for (NSObject *entity in entities) {
        NSString *sql = [self createUpdateSql:entity key:key inTable:table];
        [sqls addObject:sql];
    }
    return [self excuteSQLs:sqls operateType:DaoOperateTypeUpdate];
}

- (NSString *)createUpdateSql:(NSObject *)entity key:(NSString *)key inTable:(NSString *)table
{
    NSArray *properties = [entity getPropertyList];
    NSMutableString *sql = [[NSMutableString alloc] init];
    [sql appendFormat:@"update %@ SET ",table] ;
    NSInteger i = 0;
    
    for (NSString *key in properties) {
        if ([key isEqualToString:@"uid"]) {
            continue;
        }
        if (i>0) {
            [sql appendString:@","];
        }
        [sql appendFormat:@"%@ = '%@'",key ,[entity valueForKey:key]];
        i++;
    }
    [sql appendFormat:@" WHERE %@ = %@",key ,[entity valueForKey:key]];
    
    DLog(@"createUpdateSql  %@, entity %@", sql, entity);
    
    return sql;
}

//DELETE
- (BOOL)deleteData:(NSObject *)entity key:(NSString *)key inTable:(NSString *)table
{
    NSString *sql = [NSString stringWithFormat:@"Delete From %@ where %@=%@", table, key, [entity valueForKey:key]];
    return [self excuteSQL:sql operateType:DaoOperateTypeDelete];
}

- (BOOL)deleteDatas:(NSArray *)entities key:(NSString *)key inTable:(NSString *)table
{
    NSMutableArray *sqls = [NSMutableArray array];
    for (NSObject *entity in entities) {
        NSString *sql = [NSString stringWithFormat:@"Delete From %@ where %@=%@", table, key, [entity valueForKey:key]];
        [sqls addObject:sql];
    }
    return [self excuteSQLs:sqls operateType:DaoOperateTypeDelete];
}

@end
