//
//  FMDTSchema.m
//  FMDataTable
//
//  Created by bing.hao on 16/3/8.
//  Copyright 漏 2016骞?bing.hao. All rights reserved.
//

#import "FMDTSchema.h"
#import "NSObject+runtime.h"
#import "FMDTObject.h"

#define FMDT_DB_TYPE_TEXT   @"text"
#define FMDT_DB_TYPE_NUMBER @"integer"
#define FMDT_DB_TYPE_BLOB   @"blob"
#define FMDT_DB_TYPE_DATE   @"date"

#define FMDT_DTS_F_OBJ_NAME @"__DTS_F_OBJ_NAME"
#define FMDT_DTS_F_OBJ_TYPE @"__DTS_F_OBJ_TYPE"
#define FMDT_DTS_F_NAME     @"__DTS_F_NAME"
#define FMDT_DTS_F_TYPE     @"__DTS_F_TYPE"

BOOL FMDT_IsCollectionObject(NSString *type) {
    if ([type isEqualToString:@"T@\"NSDictionary\""] ||
        [type isEqualToString:@"T@\"NSMutableDictionary\""] ||
        [type isEqualToString:@"T@\"NSArray\""] ||
        [type isEqualToString:@"T@\"NSMutableArray\""]) {
        return YES;
    }
    return NO;
}

BOOL FMDT_IsDateObject(NSString *type) {
    if ([type isEqualToString:@"T@\"NSDate\""]) {
        return YES;
    }
    return NO;
}

BOOL FMDT_IsDataObject(NSString *type) {
    if ([type isEqualToString:@"T@\"NSData\""]) {
        return YES;
    }
    return NO;
}

NSDictionary * FMDTNewField(NSString *name, NSString *type)
{
    static NSDictionary *__map;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        __map = @{ @"T@\"NSString\"":FMDT_DB_TYPE_TEXT,
                   @"T@\"NSNumber\"":FMDT_DB_TYPE_NUMBER,
                   @"T@\"NSDate\"":FMDT_DB_TYPE_DATE,
                   @"T@\"NSData\"":FMDT_DB_TYPE_BLOB,
                   @"Ti":FMDT_DB_TYPE_NUMBER,
                   @"T^i":FMDT_DB_TYPE_NUMBER,
                   @"Tf":FMDT_DB_TYPE_NUMBER,
                   @"Tq":FMDT_DB_TYPE_NUMBER,
                   @"Td":FMDT_DB_TYPE_NUMBER,
                   @"T@\"NSDictionary\"":FMDT_DB_TYPE_TEXT,
                   @"T@\"NSMutableDictionary\"":FMDT_DB_TYPE_TEXT,
                   @"T@\"NSArray\"":FMDT_DB_TYPE_TEXT,
                   @"T@\"NSMutableArray\"":FMDT_DB_TYPE_TEXT,
                   };
    });
    NSString *dbType = [__map objectForKey:type];
    if (dbType) {
        return @{ FMDT_DTS_F_OBJ_NAME:name, FMDT_DTS_F_OBJ_TYPE : type, FMDT_DTS_F_NAME:name, FMDT_DTS_F_TYPE:dbType };
    }
    return nil;
}

@implementation FMDTSchemaTable

- (NSString *)statementUpdate {
    if (_statementUpdate == nil) {
        
        Class cls = NSClassFromString(self.className);
        NSString *pk = [(id)cls performSelector:@selector(primaryKeyFieldName) withObject:nil];
        NSAssert(pk, @"蹇呴』鎸囧畾涓婚敭瀛楁");
        
        NSMutableArray * keys = [NSMutableArray arrayWithCapacity:self.fields.count];
        for (int i = 0; i < self.fields.count; i++) {
            NSString *fname = [[self.fields objectAtIndex:i] name];
            if ([fname isEqualToString:pk] == NO) {
                [keys addObject:[NSString stringWithFormat:@"[%@]=:%@", fname, fname]];
            }
        }
        NSString * key = [keys componentsJoinedByString:@","];
        _statementUpdate = [NSString stringWithFormat:@"update [%@] set %@ where [%@]=:%@", self.tableName, key, pk, pk];
    }
    return _statementUpdate;
}

- (NSString *)statementDelete {
    if (_statementDelete == nil) {
        _statementDelete = [NSString stringWithFormat:@"delete from [%@]", self.tableName];;
    }
    return _statementDelete;
}

- (NSString *)statementInsert {
    if (_statementInsert == nil) {
        NSMutableArray * keys = [NSMutableArray arrayWithCapacity:self.fields.count];
        NSMutableArray * vals = [NSMutableArray arrayWithCapacity:self.fields.count];
        for (int i = 0; i < self.fields.count; i++) {
            FMDTSchemaField *field = self.fields[i];
            [keys addObject:[NSString stringWithFormat:@"[%@]", field.name]];
            [vals addObject:@"?"];
        }
        NSString * key = [keys componentsJoinedByString:@","];
        NSString * val = [vals componentsJoinedByString:@","];
        _statementInsert = [NSString stringWithFormat:@"insert into [%@] (%@) values (%@)", self.tableName, key, val];
    }
    return _statementInsert;
}

- (NSString *)statementReplace {
    if (_statementReplace == nil) {
        NSMutableArray * keys = [NSMutableArray arrayWithCapacity:self.fields.count];
        NSMutableArray * vals = [NSMutableArray arrayWithCapacity:self.fields.count];
        for (int i = 0; i < self.fields.count; i++) {
            FMDTSchemaField *field = self.fields[i];
            [keys addObject:[NSString stringWithFormat:@"[%@]", field.name]];
            [vals addObject:@"?"];
        }
        NSString * key = [keys componentsJoinedByString:@","];
        NSString * val = [vals componentsJoinedByString:@","];
        _statementReplace = [NSString stringWithFormat:@"replace into [%@] (%@) values (%@)", self.tableName, key, val];
    }
    return _statementReplace;
}

- (instancetype)initWithClass:(Class)cls storage:(NSString *)storage {
    self = [super init];
    if (self) {
        self.className = NSStringFromClass(cls);
        self.tableName = self.className;
        self.storage = storage;
        
        NSString *pk = [(id)cls performSelector:@selector(primaryKeyFieldName) withObject:nil];
        
        NSMutableArray * fields = [NSMutableArray new];
        [NSObject enumeratePropertiesWithClassType:cls usingBlick:^(BOOL read, NSString *name, NSString *type, NSArray *attrs) {
            NSDictionary * item = nil;
            if (!read && (item = FMDTNewField(name, type))) {
                FMDTSchemaField *field = [[FMDTSchemaField alloc] initWithDictionary:item];
                if (pk && [field.objName isEqualToString:pk]) {
                    field.primaryKey = YES;
                }
                [fields addObject:field];
            }
        }];
        
        self.fields = fields;
    }
    return self;
}

- (instancetype)initWithClass:(Class)cls customTableName:(NSString *)name storage:(NSString *)storage {
    self = [self initWithClass:cls storage:storage];
    if (self) {
        self.tableName = name;
    }
    return self;
}

@end

@implementation FMDTSchemaField

- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
    self = [super init];
    if (self) {
        self.objName = [dictionary objectForKey:FMDT_DTS_F_OBJ_NAME];
        self.objType = [dictionary objectForKey:FMDT_DTS_F_OBJ_TYPE];
        self.name = [dictionary objectForKey:FMDT_DTS_F_NAME];
        self.type = [dictionary objectForKey:FMDT_DTS_F_TYPE];
    }
    return self;
}

@end
// 鐗堟潈灞炰簬鍘熶綔鑰?// http://code4app.com (cn) http://code4app.net (en)
// 鍙戝竷浠g爜浜庢渶涓撲笟鐨勬簮鐮佸垎浜綉绔? Code4App.com