#import <Foundation/Foundation.h>
#import "yocto_api.h"
#import "yocto_display.h"



static void usage(void)
{
  NSLog(@"usage: demo <serial_number> ");
  NSLog(@"       demo <logical_name>");
  NSLog(@"       demo any                 (use any discovered device)");
  exit(1);
}

// this is the recusive function to draw 1/3nd of the Von Koch flake
static void recursiveLine(YDisplayLayer *layer, double x0, double y0, double x1,
                          double y1, int deep)
{
  double dx, dy, mx, my;
  if (deep <= 0) {
    [layer moveTo:(int)(x0 + 0.5) :(int)(y0 + 0.5)];
    [layer lineTo:(int)(x1 + 0.5) :(int)(y1 + 0.5)];
  } else {
    dx = (x1 - x0) / 3;
    dy = (y1 - y0) / 3;
    mx = ((x0 + x1) / 2) + (0.87 * (y1 - y0) / 3);
    my = ((y0 + y1) / 2) - (0.87 * (x1 - x0) / 3);
    recursiveLine(layer, x0, y0, x0 + dx, y0 + dy, deep - 1);
    recursiveLine(layer, x0 + dx, y0 + dy, mx, my, deep - 1);
    recursiveLine(layer, mx, my, x1 - dx, y1 - dy, deep - 1);
    recursiveLine(layer, x1 - dx, y1 - dy, x1, y1, deep - 1);
  }
}




int main(int argc, const char * argv[])
{
  NSError *error;
  YDisplay *disp;
  YDisplayLayer *l1, *l2;
  @autoreleasepool {

    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb": &error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@", [error localizedDescription]);
      usage();
      return 1;
    }
    if(argc < 2) {
      disp = [YDisplay FirstDisplay];
      if(disp == nil) {
        NSLog(@"No module connected (check USB cable)");
        usage();
        return 1;
      }
    } else {
      NSString *target = [NSString stringWithUTF8String:argv[1]];

      disp = [YDisplay FindDisplay:target];
      if(![disp isOnline]) {
        NSLog(@"Module not connected (check identification and USB cable)");
        usage();
        return 1;
      }
    }
    // display clean up
    [disp resetAll];
    l1 = [disp get_displayLayer:1];
    l2 = [disp get_displayLayer:2];
    [l1 hide];    // L1 is hidden, l2 stay visible
    double centerX = [disp get_displayWidth] / 2;
    double centerY = [disp get_displayHeight] / 2;
    double radius = [disp get_displayHeight] / 2;
    double a = 0;
    while (true) {
      // we draw in the hidden layer
      [l1 clear];
      for (int i = 0; i < 3; i++) {
        recursiveLine(l1, centerX + radius * cos(a + i * 2.094),
                      centerY + radius * sin(a + i * 2.094),
                      centerX + radius * cos(a + (i + 1) * 2.094),
                      centerY + radius * sin(a + (i + 1) * 2.094), 2);
      }
      // then we swap contents with the visible layer
      [disp swapLayerContent:1 :2];
      // change the flake angle
      a += 0.1257;
    }
  }

  return 0;
}
