#include "pbio/Context.h"
#import <Foundation/Foundation.h>
#import "Context.h"


#import "TryCatch.mm"
#include <fstream>


@implementation Context

-(nonnull instancetype) init: (void*) context{
    _ptr = context;
    return self;
}

-(void) dealloc{
    delete static_cast<pbio::Context*>(_ptr);
}

-(void* _Nonnull) ptr{
    return _ptr;
}

-(void) setLong: (int64_t) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context = value);
}


-(void) setDouble: (double) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context = value);
}
-(void) setBool: (bool) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context = value);
}
-(void) setString: (NSString *_Nonnull) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context = [value UTF8String]);
}

-(void) setDataPtr: (const uint8_t *_Nullable) value : (int) copy_sz{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.setDataPtr(value, copy_sz));
}

-(void) setNSData: (NSData* _Nonnull) data{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    const void* buffer = [data bytes];
    size_t len = [data length];
    
    tryCatch(context.setDataPtr(buffer, int(len)));
}

-(void) setContextTemplate: (ContextTemplate* _Nonnull) value
{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    pbio::ContextTemplate::Ptr& templ = *(static_cast<pbio::ContextTemplate::Ptr*>(value.ptr));
    tryCatch(context.setContextTemplate(templ));
}

-(void) setDynamicTemplateIndex: (DynamicTemplateIndex* _Nonnull) value
{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    pbio::DynamicTemplateIndex::Ptr& templ_index = *(static_cast<pbio::DynamicTemplateIndex::Ptr*>(value.ptr));
    tryCatch(context.setDynamicTemplateIndex(templ_index));
}


-(ContextTemplate* _Nonnull) getContextTemplate{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    pbio::ContextTemplate::Ptr templ = tryCatch(context.getContextTemplate());
    return [[ContextTemplate alloc] init: new pbio::ContextTemplate::Ptr(std::move(templ))];
}

-(DynamicTemplateIndex* _Nonnull) getDynamicTemplateIndex{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    pbio::DynamicTemplateIndex::Ptr templ_index = tryCatch(context.getDynamicTemplateIndex());
    return [[DynamicTemplateIndex alloc] init: new pbio::DynamicTemplateIndex::Ptr(std::move(templ_index))];
}

-(bool) isContextTemplate{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isContextTemplate());
}

-(bool) isDynamicTemplateIndex{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isDynamicTemplateIndex());
}

-(void) set: (Context* _Nonnull) other{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    const pbio::Context& other_context = *(static_cast<pbio::Context*>(other->_ptr));
    tryCatch(context = other_context);
}

-(int64_t) getLong{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.getLong());
}

-(double) getDouble{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.getDouble());
}

-(bool) getBool{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.getBool());
}

-(NSString *_Nonnull) getString{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    std::string value = tryCatch(context.getString());
    return [NSString stringWithUTF8String:value.c_str()];
}

-(uint8_t* _Nonnull) getDataPtr{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    uint8_t *result = tryCatch(context.getDataPtr());
    return result;
}

-(const NSData* _Nonnull) getNSData: (int64_t) size{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    void* blob_data = static_cast<void*>(tryCatch(context.getDataPtr()));
    return [[NSData alloc] initWithBytesNoCopy:blob_data length:size freeWhenDone:false];
}


-(Context* _Nonnull) at: (int) index{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    
    pbio::ContextRef* at_context = tryCatch(context[index].getContextPtr());
    
    return [[Context alloc] init: at_context];
}

-(Context* _Nonnull) get: (NSString *_Nonnull) key{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    pbio::ContextRef* at_context = tryCatch(context[[key UTF8String]].getContextPtr());
    
    return [[Context alloc] init: static_cast<void*>(at_context)];
}

-(size_t) size{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.size());
}

-(bool) contains: (NSString *_Nonnull) key{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.contains(std::string([key UTF8String])));
}

-(bool) compare: (Context *_Nonnull)  other{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    pbio::Context& other_context = *(static_cast<pbio::Context*>(other->_ptr));
    
    return tryCatch(context.compare(other_context));
    
}
-(void) clear{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.clear());
    
}
-(void) erase: (NSString *_Nonnull) key{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.erase([key UTF8String]));
}
-(void) reserve: (size_t) size{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.reserve(size));
}

-(void) saveToJsonFile: (NSString *_Nonnull) path{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.saveToJsonFile([path UTF8String]));
}

-(nonnull NSMutableArray*) getKeys{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    std::vector<std::string> keys = tryCatch(context.getKeys());
    NSMutableArray *result = [NSMutableArray new];
    
    for (auto& key : keys){
        NSString *tmp_string = [NSString stringWithCString: key.c_str()
                                           encoding:[NSString defaultCStringEncoding]];
        [result addObject: tmp_string];
    }
    
    return result;
}

-(void) pushBack: (Context *_Nonnull) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    pbio::Context& value_context = *(static_cast<pbio::Context*>(value->_ptr));
    tryCatch(context.push_back(value_context));
}
-(void) pushBackLong: (int64_t) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.push_back(value));
}
-(void) pushBackDouble: (double) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.push_back(value));
}
-(void) pushBackBool: (bool) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.push_back(value));
}
-(void) pushBackString: (NSString *_Nonnull) value{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    tryCatch(context.push_back(value));
}

-(bool) isNone{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isNone());
}
-(bool) isObject{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isObject());
}

-(bool) isArray{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isArray());
}

-(bool) isBool{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isBool());
}
-(bool) isString{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isString());
}
-(bool) isDouble{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isDouble());
}
-(bool) isLong{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isLong());
}
-(bool) isDataPtr{
    pbio::Context& context = *(static_cast<pbio::Context*>(_ptr));
    return tryCatch(context.isDataPtr());
}

@end
