//  BlockyFroggy
//  Copyright © 2017 John Ryland.
//  All rights reserved.
#import "GameViewController.h"
#import <OpenGLES/ES2/glext.h>
#include "Log.h"
#include "Debug.h"
#include "GameScreen.h"
#include "GameAudio.h"
#include "SystemInformation.h"
#include "TargetConditionals.h"
#include <fstream>


void loadPlatformFile(const char* filename, std::vector<uint8_t>& data)
{
  data.clear();
  NSString *fname = [NSString stringWithUTF8String:filename];
  NSString* fileName = [fname stringByDeletingPathExtension];
  NSString* extension = [fname pathExtension];
  NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
#if 1
  NSData *nsData = [NSData dataWithContentsOfFile:filePath];
  if (nsData) {
    const uint8_t* d = (const uint8_t*)[nsData bytes];
    data.assign(d, d + [nsData length]);
#else
  //NSData *nsData = [NSData dataWithContentsOfFile:filePath];
  //int len = [nsData length];
  const char* fileStr = [filePath UTF8String];
  std::ifstream file(fileStr, std::ios::binary);
  if (!file.fail()) {
    file.seekg(0, std::ios::end);
    data.resize(file.tellg());
    file.seekg(0, std::ios::beg);
    file.read((char*)data.data(), data.size());
    file.close();
    LogTag(LL_Error, "LDR", "lens: %lu", data.size());
#endif
  } else {
    LogTag(LL_Error, "LDR", "Couldn't load %s file", filename);
  }
}


DECLARE_LOG_CONTEXT(CTX)


@interface GameViewController ()
{
    SystemInformation m_sysInfo;
    GameScreen m_screen;
    BOOL _bannerIsVisible;
    //ADBannerView *bannerView;
    GameAudioRenderer m_audio;
}
@property (nonatomic, assign) BOOL bannerIsVisible;
@property (strong, nonatomic) EAGLContext *context;
- (void)close;
@end


class EAGLContextWrapper
{
public:
  EAGLContextWrapper();
  
private:
  EAGLContext *m_context;
};


@implementation GameViewController

- (void)viewDidLoad
{
#if 0
    if ([ADBannerView instancesRespondToSelector:@selector(initWithAdType:)]) {
      bannerView = [[ADBannerView alloc] initWithAdType:ADAdTypeBanner];
    } else {
      bannerView = [[ADBannerView alloc] init];
    }
    
/*
    //bannerView = [[ADBannerView alloc] initWithFrame:CGRectZero];
    bannerView.frame = CGRectOffset(adView.frame, 0, -50);
    bannerView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifierPortrait];
    bannerView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
*/
    
    const bool showAds = true;
    if (showAds)
    {
        bannerView.delegate=self;
        //[self.view addSubview:bannerView];
        
        //bannerView.bottomAnchor
        //bannerView.centerXAnchor
        CGRect adFrame = bannerView.frame;
        adFrame.origin.y = self.view.frame.size.height - bannerView.frame.size.height;
        adFrame.origin.x = (self.view.frame.size.width - bannerView.frame.size.width) / 2;
        bannerView.frame = adFrame;
        [self.view addSubview:bannerView];

        self.bannerIsVisible=NO;        
    }
#endif
  
    [super viewDidLoad];
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    if (!self.context) {
        Log(LL_Error, "Failed to create ES context");
    }
    GLKView *view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
  
    //view.preferredFramesPerSecond = 60.0;
  
    self.preferredFramesPerSecond = 60.0;//62;

    Log(LL_Info, "setupGL");
    [EAGLContext setCurrentContext:self.context];
    m_screen.initialize();

#if !TARGET_IPHONE_SIMULATOR
    m_audio.initialize(SampleRate_44100Hz, Bits_16, Stereo);//Mono);
    m_audio.start();
#endif

    self.context.multiThreaded = TRUE;
}

- (void)dealloc
{
    [self close];
}

- (void)close
{
    Log(LL_Info, "tearDownGL");
    [EAGLContext setCurrentContext:self.context];
    m_screen.shutdown();
    if ([EAGLContext currentContext] == self.context) {
        [EAGLContext setCurrentContext:nil];
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    if ([self isViewLoaded] && ([[self view] window] == nil)) {
        self.view = nil;
        [self close];
        self.context = nil;
    }
    // Dispose of any resources that can be recreated.
    m_screen.freeSpace();
}

- (BOOL)prefersStatusBarHidden
{
    return YES;
}

- (void)update
{
    AllocationTracking::g_enableAllocTracing = true;

    //! @todo remove the time scaling
    m_screen.update(5.0f * self.timeSinceLastUpdate, fabs(self.view.bounds.size.width / self.view.bounds.size.height));
}

#include <malloc/malloc.h>
#include "Utilities.h"

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    AllocationTracking::g_enableAllocTracing = true;
/*
    malloc_zone_t *zone = malloc_default_zone();
    malloc_statistics_t stats;
    malloc_zone_statistics(zone, &stats);

    setDebugValue("AllocBlkIU:", std::to_string(stats.blocks_in_use).c_str());
    setDebugValue("AllocSizeA:", std::to_string(stats.size_allocated).c_str());
    setDebugValue("AllocInUse:", std::to_string(stats.size_in_use).c_str());
    setDebugValue("AllocMaxIU:", std::to_string(stats.max_size_in_use).c_str());
*/
    setDebugValue("AllocFrame:", std::to_string(AllocationTracking::frameAllocations).c_str());
    setDebugValue("AllocSet:",   std::to_string(AllocationTracking::allocationCount - AllocationTracking::deallocationCount).c_str());
    setDebugValue("AllocTotal:", std::to_string(AllocationTracking::allocationCount).c_str());
    setDebugValue("AllocFrees:", std::to_string(AllocationTracking::deallocationCount).c_str());
    AllocationTracking::frameAllocations = 0;


    setDebugValue("CPU Usage:", m_sysInfo.getCpuUsage());
    setDebugValue("Memory Usage:", std::string(std::to_string(m_sysInfo.getMemoryUsage()) + " bytes").c_str());
    setDebugValue("Frame time:", std::string(std::to_string(m_sysInfo.getFrameTime() * 1000.0) + " ms").c_str());
    setDebugValue("Draw time:", std::string(std::to_string(m_sysInfo.getDrawTime() * 1000.0) + " ms").c_str());
    setDebugValue("FPS:", m_sysInfo.getFps());
    setDebugValue("Average FPS:", m_sysInfo.getAverageFps());
    setDebugValue("W:", int(self.view.frame.size.width  * self.view.contentScaleFactor));
    setDebugValue("H:", int(self.view.frame.size.height * self.view.contentScaleFactor));

    m_sysInfo.preDraw();
    m_screen.draw();
    m_sysInfo.frameDrawn();
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint touchLocation = [touch locationInView:touch.view];
    float s = touch.view.contentScaleFactor;
    //! @todo remove the need for these constants
    // What this is doing is treating the screen as some fixed size, but scaling the actual values to
    // this arbitary resolution that everything has been hard-coded to. Will be hard to undo this. Perhaps
    // make the arbitary resolution be 1.0 x 1.0 and then scale everything else accordingly and call it
    // normalized coordinates. Then it won't be biased to portrait / landscape.
    float xs = 2*640.0 / (self.view.frame.size.width * s); // iPhone 5s res is 640 x 1136
    float ys = 2*960.0 / (self.view.frame.size.height * s);
    m_screen.touchDown(touchLocation.x*xs, touchLocation.y*ys);
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint touchLocation = [touch locationInView:touch.view];
    float s = touch.view.contentScaleFactor;
    float xs = 2*640.0 / (self.view.frame.size.width * s);
    float ys = 2*960.0 / (self.view.frame.size.height * s);
    m_screen.touchUp(touchLocation.x*xs, touchLocation.y*ys);
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint touchLocation = [touch locationInView:touch.view];
    float s = touch.view.contentScaleFactor;
    float xs = 2*640.0 / (self.view.frame.size.width * s);
    float ys = 2*960.0 / (self.view.frame.size.height * s);
    m_screen.touchMove(touchLocation.x*xs, touchLocation.y*ys);
}

@end
