//
//  LKDBProperty+KeyMapping.m
//  LKDBHelper
//
//  Created by LJH on 13-6-17.
//  Copyright (c) 2013年 ljh. All rights reserved.
//

#import "LKDB+Mapping.h"
#import "NSObject+LKModel.h"

@interface LKModelInfos () {
    __strong NSMutableDictionary* _proNameDic;
    __strong NSMutableDictionary* _sqlNameDic;
    __strong NSArray* _primaryKeys;
}
- (void)removeWithColumnName:(NSString*)columnName;
- (void)addDBPropertyWithType:(NSString*)type cname:(NSString*)column_name ctype:(NSString*)ctype pname:(NSString*)pname ptype:(NSString*)ptype;

- (void)updateProperty:(LKDBProperty*)property sqlColumnName:(NSString*)columnName;
- (void)updateProperty:(LKDBProperty*)property propertyName:(NSString*)propertyName;
@end

#pragma mark - 声明属性
@interface LKDBProperty ()
@property (copy, nonatomic) NSString* type;

@property (copy, nonatomic) NSString* sqlColumnName;
@property (copy, nonatomic) NSString* sqlColumnType;

@property (copy, nonatomic) NSString* propertyName;
@property (copy, nonatomic) NSString* propertyType;

- (id)initWithType:(NSString*)type cname:(NSString*)cname ctype:(NSString*)ctype pname:(NSString*)pname ptype:(NSString*)ptype;
@end
#pragma mark - LKDBProperty
@implementation LKDBProperty

- (id)initWithType:(NSString*)type cname:(NSString*)cname ctype:(NSString*)ctype pname:(NSString*)pname ptype:(NSString*)ptype
{
    self = [super init];
    if (self) {
        _type = [type copy];
        _sqlColumnName = [cname copy];
        _sqlColumnType = [ctype copy];
        _propertyName = [pname copy];
        _propertyType = [ptype copy];
    }
    return self;
}
- (void)enableUserCalculate
{
    _type = LKSQL_Mapping_UserCalculate;
}
- (BOOL)isUserCalculate
{
    return ([_type isEqualToString:LKSQL_Mapping_UserCalculate] || _propertyName == nil || [_propertyName isEqualToString:LKSQL_Mapping_UserCalculate]);
}
@end
#pragma mark - NSObject - TableMapping
@implementation NSObject (TableMapping)
+ (NSDictionary*)getTableMapping
{
    return nil;
}
+ (void)setUserCalculateForCN:(NSString*)columnName
{
    if ([LKDBUtils checkStringIsEmpty:columnName]) {
        LKErrorLog(@"columnName is null");
        return;
    }

    LKModelInfos* infos = [self getModelInfos];
    LKDBProperty* property = [infos objectWithSqlColumnName:columnName];
    if (property) {
        [property enableUserCalculate];
    }
    else {
        [infos addDBPropertyWithType:LKSQL_Mapping_UserCalculate cname:columnName ctype:LKSQL_Type_Text pname:columnName ptype:@"NSString"];
    }
}
+ (void)setUserCalculateForPTN:(NSString*)propertyTypeName
{
    if ([LKDBUtils checkStringIsEmpty:propertyTypeName]) {
        LKErrorLog(@"propertyTypeName is null");
        return;
    }

    Class clazz = NSClassFromString(propertyTypeName);
    LKModelInfos* infos = [self getModelInfos];
    for (NSInteger i = 0; i < infos.count; i++) {
        LKDBProperty* property = [infos objectWithIndex:i];

        Class p_cls = NSClassFromString(property.propertyType);
        BOOL isSubClass = ((p_cls && clazz) && [p_cls isSubclassOfClass:clazz]);
        BOOL isNameEqual = [property.propertyType isEqualToString:propertyTypeName];
        if (isSubClass || isNameEqual) {
            [property enableUserCalculate];
        }
    }
}
+ (void)setTableColumnName:(NSString*)columnName bindingPropertyName:(NSString*)propertyName
{
    if ([LKDBUtils checkStringIsEmpty:columnName] || [LKDBUtils checkStringIsEmpty:propertyName])
        return;

    LKModelInfos* infos = [self getModelInfos];

    LKDBProperty* property = [infos objectWithPropertyName:propertyName];
    if (property == nil) {
        return;
    }

    LKDBProperty* column = [infos objectWithSqlColumnName:columnName];
    if (column) {
        [infos updateProperty:column propertyName:propertyName];
        column.propertyType = property.propertyType;
    }
    else if ([property.sqlColumnName isEqualToString:property.propertyName]) {
        [infos updateProperty:property sqlColumnName:columnName];
    }
    else {
        [infos addDBPropertyWithType:LKSQL_Mapping_Binding cname:columnName ctype:LKSQL_Type_Text pname:propertyName ptype:property.propertyType];
    }
}
+ (void)removePropertyWithColumnNameArray:(NSArray*)columnNameArray
{
    LKModelInfos* infos = [self getModelInfos];
    for (NSString* columnName in columnNameArray) {
        [infos removeWithColumnName:columnName];
    }
}
+ (void)removePropertyWithColumnName:(NSString*)columnName
{
    [[self getModelInfos] removeWithColumnName:columnName];
}
@end

#pragma mark - LKModelInfos

@implementation LKModelInfos
- (id)initWithKeyMapping:(NSDictionary*)keyMapping propertyNames:(NSArray*)propertyNames propertyType:(NSArray*)propertyType primaryKeys:(NSArray*)primaryKeys
{
    self = [super init];
    if (self) {

        _primaryKeys = [NSArray arrayWithArray:primaryKeys];

        _proNameDic = [[NSMutableDictionary alloc] init];
        _sqlNameDic = [[NSMutableDictionary alloc] init];

        NSString *type, *column_name, *column_type, *property_name, *property_type;
        if (keyMapping.count > 0) {
            NSArray* sql_names = keyMapping.allKeys;

            for (NSInteger i = 0; i < sql_names.count; i++) {

                type = column_name = column_type = property_name = property_type = nil;

                column_name = [sql_names objectAtIndex:i];
                NSString* mappingValue = [keyMapping objectForKey:column_name];

                //如果 设置的 属性名 是空白的  自动转成 使用ColumnName
                if ([LKDBUtils checkStringIsEmpty:mappingValue]) {
                    NSLog(@"#ERROR sql column name %@ mapping value is empty,automatically converted LKDBInherit", column_name);
                    mappingValue = LKSQL_Mapping_Inherit;
                }

                if ([mappingValue isEqualToString:LKSQL_Mapping_UserCalculate]) {
                    type = LKSQL_Mapping_UserCalculate;
                    column_type = LKSQL_Type_Text;
                }
                else {

                    if ([mappingValue isEqualToString:LKSQL_Mapping_Inherit] || [mappingValue isEqualToString:LKSQL_Mapping_Binding]) {
                        type = LKSQL_Mapping_Inherit;
                        property_name = column_name;
                    }
                    else {
                        type = LKSQL_Mapping_Binding;
                        property_name = mappingValue;
                    }

                    NSUInteger index = [propertyNames indexOfObject:property_name];

                    NSAssert(index != NSNotFound, @"#ERROR TableMapping SQL column name %@ not fount %@ property name", column_name, property_name);

                    property_type = [propertyType objectAtIndex:index];
                    column_type = LKSQLTypeFromObjcType(property_type);
                }

                [self addDBPropertyWithType:type cname:column_name ctype:column_type pname:property_name ptype:property_type];
            }
        }
        else {
            for (NSInteger i = 0; i < propertyNames.count; i++) {

                type = LKSQL_Mapping_Inherit;

                property_name = [propertyNames objectAtIndex:i];
                column_name = property_name;

                property_type = [propertyType objectAtIndex:i];
                column_type = LKSQLTypeFromObjcType(property_type);

                [self addDBPropertyWithType:type cname:column_name ctype:column_type pname:property_name ptype:property_type];
            }
        }

        if (_primaryKeys.count == 0) {
            _primaryKeys = [NSArray arrayWithObject:@"rowid"];
        }

        for (NSString* pkname in _primaryKeys) {
            if ([pkname.lowercaseString isEqualToString:@"rowid"]) {
                if ([self objectWithSqlColumnName:pkname] == nil) {
                    [self addDBPropertyWithType:LKSQL_Mapping_Inherit cname:pkname ctype:LKSQL_Type_Int pname:pkname ptype:@"int"];
                }
            }
        }
    }
    return self;
}
- (void)addDBPropertyWithType:(NSString*)type cname:(NSString*)column_name ctype:(NSString*)ctype pname:(NSString*)pname ptype:(NSString*)ptype
{
    LKDBProperty* db_property = [[LKDBProperty alloc] initWithType:type cname:column_name ctype:ctype pname:pname ptype:ptype];

    if (db_property.propertyName) {
        [_proNameDic setObject:db_property forKey:db_property.propertyName];
    }
    if (db_property.sqlColumnName) {
        [_sqlNameDic setObject:db_property forKey:db_property.sqlColumnName];
    }
}
- (NSArray*)primaryKeys
{
    return _primaryKeys;
}
- (NSUInteger)count
{
    return _sqlNameDic.count;
}
- (LKDBProperty*)objectWithIndex:(NSInteger)index
{
    if (index < _sqlNameDic.count) {
        id key = [_sqlNameDic.allKeys objectAtIndex:index];
        return [_sqlNameDic objectForKey:key];
    }
    return nil;
}
- (LKDBProperty*)objectWithPropertyName:(NSString*)propertyName
{
    return [_proNameDic objectForKey:propertyName];
}
- (LKDBProperty*)objectWithSqlColumnName:(NSString*)columnName
{
    return [_sqlNameDic objectForKey:columnName];
}

- (void)updateProperty:(LKDBProperty*)property propertyName:(NSString*)propertyName
{
    [_proNameDic removeObjectForKey:property.propertyName];
    property.propertyName = propertyName;
    [_proNameDic setObject:property forKey:propertyName];
}
- (void)updateProperty:(LKDBProperty*)property sqlColumnName:(NSString*)columnName
{
    [_sqlNameDic removeObjectForKey:property.sqlColumnName];
    property.sqlColumnName = columnName;
    [_sqlNameDic setObject:property forKey:columnName];
}
- (void)removeWithColumnName:(NSString*)columnName
{
    if ([LKDBUtils checkStringIsEmpty:columnName])
        return;

    LKDBProperty* property = [_sqlNameDic objectForKey:columnName];
    if (property.propertyName) {
        [_proNameDic removeObjectForKey:property.propertyName];
    }
    [_sqlNameDic removeObjectForKey:columnName];
}
@end