//
//  Unre3DImpl.m
//  UnretekFace3D
//
//  Created by chenxinguo on 2018/11/1.
//  Copyright © 2018 Unre（Shanghai）Information Technology Co., Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>

#import  "Unre3DImpl.h"
#include "UnOBJUtils.h"
#import "Unre3DARCaptureConfig.h"
const int SELECT_CONFIG_SUM = 7;
int selectconfig[SELECT_CONFIG_SUM] = {0,0,0,0,0};
@interface Unre3DCameraII()
-(UIImage *)fixOrientation:(UIImage *)aImage;
@end

@implementation Unre3DCameraII
- (instancetype)initWithVideoOrientation:(Unre3DCameraVideoOrientation)orientation
{
    if(self == [super initWithVideoOrientation:orientation]){
        //self.delegate = self;
        //[self addObserver:self];
    }
    return self;
}

-(UIImage *)fixOrientation:(UIImage *)aImage
{
    if(aImage.imageOrientation==UIImageOrientationUp)
        return aImage;
    CGAffineTransform transform = CGAffineTransformIdentity;
    switch(aImage.imageOrientation){
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform,aImage.size.width,aImage.size.height);
            transform = CGAffineTransformRotate(transform,M_PI);
            break;
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform,aImage.size.width,0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        default:
            break;
            
    }
    switch(aImage.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        default:
            break;
            
    }
    CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
                                             CGImageGetBitsPerComponent(aImage.CGImage), 0,
                                             CGImageGetColorSpace(aImage.CGImage),
                                             CGImageGetBitmapInfo(aImage.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (aImage.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
            break;
        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
            break;
            
    }
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}



@end
/////////////////////////////////////////Unre3DCameraII//////////////////////////////////////////////////////
@interface UnreScannerII()<Unre3DHeadScannerObserver>
@property(nonatomic,strong) Unre3DCameraII * unre3DCamera;
@property(nonatomic,strong) Unre3DHeadScanner *headScanner;
@property(nonatomic,strong) Unre3DHeadScannerSessionData * sessionData;
@property(nonatomic,assign) BOOL debug;
@end

@implementation UnreScannerII

-(instancetype) init
{
    self = [super init];
    if (self) {
        _debug = YES;
        [self commitUnre3DScannerInit];
    }
    return self;
}

- (void) commitUnre3DScannerInit
{
    if(self.debug){
        NSLog(@"Unre3DScanner commitUnre3DScannerInit %@", [self debugUnre3DScanner]);
    }
}

///UnreSDK  must be modify
- (BOOL) setPreviewUIView:(UIView *)previewUIView
{
    if(self.debug){
        NSLog(@"Unre3DScanner setPreviewUIView");
    }
    [self.unre3DCamera startStreaming:previewUIView];
    return YES;
}

///////////////////////////////
- (Unre3DHeadScannerState) getCurrentBellus3DScannerState
{
    return self.headScanner.state;
}

- (NSString *) debugUnre3DScanner
{
    return [NSString stringWithFormat:@"{rootSessionDirectory:%@, sessionID:%@}",
            self.sessionData.rootSessionDirectory,
            self.sessionData.sessionID];
}

///////////////////////////////
- (Unre3DCameraII *) unre3DCamera
{
    if(!_unre3DCamera){
        _unre3DCamera = [[Unre3DCameraII alloc] initWithVideoOrientation:Unre3DCameraVideoOrientationPortraitUp];
    }
    return _unre3DCamera;
}

- (Unre3DHeadScannerSessionData *) sessionData
{
    if(!_sessionData){
        NSString * unrecapturepath = [[Unre3DARCaptureConfig sharedInstance] getCustomCaptureTempPath];
        //[Unre3DARCaptureConfig createPath:unrecapturepath];//make sure its exist.
        _sessionData = [Unre3DHeadScannerSessionData dataWithID:unrecapturepath];
    }
    return _sessionData;
}

- (Unre3DHeadScanner *) headScanner
{
    if(!_headScanner){
        _headScanner = [[Unre3DHeadScanner alloc] initWithCamera:self.unre3DCamera sessionData:self.sessionData];
        [_headScanner addObserver:self];
    }
    return _headScanner;
}

//////////////////////////////
- (BOOL) startScanner:(Unre3DHeadScannerSessionData*) data
{
    if(self.debug){
        NSLog(@"Unre3DScanner startScanner %@", [self debugUnre3DScanner]);
    }
    [self.headScanner startScanning];
    return YES;
}

- (BOOL) startTracking
{
    if(self.debug){
        NSLog(@"Unre3DScanner startTracking %@", [self debugUnre3DScanner]);
    }
    [self.headScanner startTracking];
    return YES;
}

- (BOOL) cancel
{
    if(self.debug){
        NSLog(@"Unre3DScanner cancel %@", [self debugUnre3DScanner]);
    }
    [self.unre3DCamera stopStreaming];
    [self.headScanner cancel];
    return YES;
}
///////////////////////////////////////////////////
- (BOOL) notifydidTrackFacePosition:(Unre3DHeadScannerFacePosition)facePosition
{
    if(_unre3DAR3DCaptureImplDelegate){
        [_unre3DAR3DCaptureImplDelegate notifyUnre3DAR3DFaceType:[self tranformUnre3DHeadScannerFacePositionToUnre3DAR3DFaceType:facePosition]];
        return YES;
    }
    return NO;
}
- (BOOL) notifydidReportProgressInfo:(Unre3DHeadScannerProgressInfo *)progressInfo
{
    if(_unre3DAR3DCaptureImplDelegate){
        [_unre3DAR3DCaptureImplDelegate notifyHeadPosition:progressInfo.currentHeadPosition];
        return YES;
    }
    return NO;
}
- (BOOL) notifydidProvideHint:(Unre3DHeadScannerScanHint)hint
{
    if(_unre3DAR3DCaptureImplDelegate){
        [_unre3DAR3DCaptureImplDelegate notifyScanHint:[self tranformUnre3DHeadScannerScanHintToUnre3DAR3DScanHint:hint]];
    }
    return NO;
}
////////////////////////////////////////////////////////////////////////////////
//for unre3DAR3DCaptureImplDelegate;
- (void) didTrackFacePosition:(Unre3DHeadScannerFacePosition)facePosition
{
    [self notifydidTrackFacePosition:facePosition];
}

- (void)didReportCountdown:(float)countdown
{
    if(_head3DScannerDelegate){
        [_head3DScannerDelegate  didReportCountdown:countdown];
    }
}

- (void)didReportProgressInfo:(Unre3DHeadScannerProgressInfo *)progressInfo
{
  
    
    [self notifydidReportProgressInfo:progressInfo];
}

- (void)didCompleteScanningSuccessfully:(BOOL)completedSuccessfully
{
    NSLog(@"Unre3DScanner didCompleteScanningSuccessfully %@",(completedSuccessfully?@"SUCCESS":@"FAIL"));
    if(_unre3DScannerDelegateH){
        [_unre3DScannerDelegateH notifyCompleteScanningSuccessfully:completedSuccessfully];
    }
    if(_head3DScannerDelegate){
        [_head3DScannerDelegate  didCompleteScanningSuccessfully:completedSuccessfully];
    }
}

- (void) didProvideHint:(Unre3DHeadScannerScanHint)hint
{
    [self notifydidProvideHint:hint];
    if(_head3DScannerDelegate){
        [_head3DScannerDelegate didProvideHint:hint];
    }
}

- (void) didEncounterError:(nullable NSError *)error
{
    NSLog(@"Unre3DScanner didEncounterError %@", error);
    ///UnreSDK dete
    /* if(_Bellus3DScannerDelegate){
     [_Bellus3DScannerDelegate headScanner:headScanner didEncounterError:error];
     }*/
}
////////////////////////////////////////
- (Unre3DAR3DFaceType) tranformUnre3DHeadScannerFacePositionToUnre3DAR3DFaceType:(Unre3DHeadScannerFacePosition)facePosition
{
    switch(facePosition){
        case Unre3DHeadScannerFacePositionFaceTooFar: return Unre3DAR3DFacePositionFaceTooFar;
        case Unre3DHeadScannerFacePositionReadyToScan: return Unre3DAR3DFacePositionReadyToScan;
        case Unre3DHeadScannerFacePositionFaceNotFound: return Unre3DAR3DFacePositionFaceNotFound;
        case Unre3DHeadScannerFacePositionFaceTooClose: return Unre3DAR3DFacePositionFaceTooClose;
        case Unre3DHeadScannerFacePositionNotAvailable: return Unre3DAR3DFacePositionNotAvailable;
        case Unre3DHeadScannerFacePositionFaceNotFrontal: return Unre3DAR3DFacePositionFaceNotFrontal;
        case Unre3DHeadScannerFacePositionFaceNotCentered: return Unre3DAR3DFacePositionFaceNotCentered;
    }
    //return [NSString stringWithFormat:@"Bellus3DAR3DFacePosition_%zi", facePosition];
}

- (Unre3DAR3DScanHint) tranformUnre3DHeadScannerScanHintToUnre3DAR3DScanHint:(Unre3DHeadScannerScanHint)hint
{
    switch(hint){
        case Unre3DHeadScannerScanHintNone: return Unre3DAR3DScanHintNone;
        case Unre3DHeadScannerScanHintHoldStill: return Unre3DAR3DScanHintHoldStill;
        case Unre3DHeadScannerScanHintCountdownThree: return Unre3DAR3DScanHintCountdownOne;
        case Unre3DHeadScannerScanHintCountdownTwo: return Unre3DAR3DScanHintCountdownTwo;
        case Unre3DHeadScannerScanHintCountdownOne: return Unre3DAR3DScanHintCountdownThree;
        case Unre3DHeadScannerScanHintTurnHeadLeft: return Unre3DAR3DScanHintTurnHeadLeft;
        case Unre3DHeadScannerScanHintTurnHeadRight: return Unre3DAR3DScanHintTurnHeadRight;
        case Unre3DHeadScannerScanHintKeepHeadTurning: return Unre3DAR3DScanHintKeepHeadTurning;
        case Unre3DHeadScannerScanHintCaptureCompleted: return Unre3DAR3DScanHintCaptureCompleted;
        case Unre3DHeadScannerScanHintCaptureAboutToStop: return Unre3DAR3DScanHintCaptureAboutToStop;
        case Unre3DHeadScannerScanHintTurnHeadToTheMiddle: return Unre3DAR3DScanHintTurnHeadToTheMiddle;
    }
}
@end
/////////////////////////////////////////UnreScannerII//////////////////////////////////////////////////////
@interface Unre3DProcessor()<Unre3DHeadProcessorObserver>
@property(nonatomic,strong) Unre3DHeadProcessor * headProcessor;
@property(nonatomic,strong) Unre3DAR3DCaptureInfo * captureInfo;
@property(nonatomic,assign) BOOL debug;
- (void) createOBJ:(Unre3DAR3DCaptureInfo*) captureInfo andUnre3DHeadScannerSessionData:(Unre3DHeadScannerSessionData *) data;
@end
@implementation Unre3DProcessor
/////////////////////////
-(instancetype) init
{
    self = [super init];
    if (self) {
        _debug = YES;
        [self commitUnre3DProcessorInit];
    }
    return self;
}

- (void) commitUnre3DProcessorInit
{
   
}

- (Unre3DHeadProcessor *)headProcessor
{
    if(!_headProcessor){
        _headProcessor = [Unre3DHeadProcessor new];
        [_headProcessor addObserver:self];
    }
    return _headProcessor;
}

- (void) createOBJ:(Unre3DAR3DCaptureInfo*) captureInfo andUnre3DHeadScannerSessionData:(Unre3DHeadScannerSessionData *) data
{
    if(self.debug){
        NSLog(@"createOBJ start");
    }
    [self removeLastState];
    self.captureInfo = captureInfo;
    //此处需要将 UnreScannerII 中的 sessionData 传进来
    [self.headProcessor processWithSessionData:data];
}

- (BOOL) removeLastState
{
    _captureInfo = nil;
    /*if(_headProcessor){
        [_headProcessor removeObserver:self];
        _headProcessor = nil;
    }*/
    return YES;
}

- (void) didReportProgress:(float)progress
{
    if(self.debug){
        //LogDebug(@"didReportProgress: %f", progress);
    }
    if(_unre3DAR3DCaptureImplDelegate){
        [_unre3DAR3DCaptureImplDelegate notifyProcessorProcessing:progress];
    }
}

- (void) didCompleteProcessingWithMesh:(nullable Unre3DHeadMesh *)headMesh
{
    if(self.debug){
        NSLog(@"didCompleteProcessingWithMesh: %@", headMesh);
    }
    if(_captureInfo){
        BOOL exportResult = NO;
        if(headMesh){
            NSString * path = _captureInfo.basePath;
            NSString * filename = [_captureInfo getFileName];
            NSLog(@"path:%@,filename:%@", path,filename);
            exportResult = [headMesh exportMeshFilesToDirectoryAtPATH:path filename:filename error:nil];
            if(exportResult && _headProcessor){
                [[[NSThread alloc] initWithTarget:self selector:@selector(reSaveOBJFileData) object:nil] start];
            } else{
                if(_unre3DProcessorDelegateH){
                    [_unre3DProcessorDelegateH notifyCompleteProcessingWithMesh:exportResult];
                }
            }
        } else {
            if(_unre3DProcessorDelegateH){
                [_unre3DProcessorDelegateH notifyCompleteProcessingWithMesh:exportResult];
            }
        }
    }

}


- (void) reSaveOBJFileData
{
    // IOS 不支持 mtl 文件，需要去除
    BOOL resaveResult = NO;
    NSString * objfilename = [_captureInfo getOBJFile];
    OBJData * source = [UnOBJUtils getOBJDataFromFile:objfilename];
    if(source){
        resaveResult = [UnOBJUtils saveOBJData:source toFile:objfilename];
    }
    NSLog(@"reSaveOBJFileData resaveResult=%@", (resaveResult?@"YES":@"NO"));
    if(_unre3DProcessorDelegateH){
        __weak Unre3DProcessor * processor = self;
        dispatch_async(dispatch_get_main_queue(), ^{
            [processor.unre3DProcessorDelegateH notifyCompleteProcessingWithMesh:resaveResult];

        });
    }
}

- (void) didEncounterError:(nullable NSError *)error
{
    NSLog(@"headProcessor didEncounterError %@", error);
}

@end


/////////////////////////////////////////Unre3DProcessor//////////////////////////////////////////////////////
@interface Unre3DImpl()<Unre3DScannerDelegate,Unre3DProcessorDelegate>
@property(nonatomic,strong) UnreScannerII * unre3DScanner;
@property(nonatomic,strong) Unre3DProcessor * unre3DProcessor;
@property(nonatomic,strong) Unre3DAR3DCaptureImpl *unre3DAR3DCaptureImpl;
@property(nonatomic,assign) BOOL canCreateOBJ;
@end

@implementation Unre3DImpl

- (instancetype) initWithUnre3DAR3DCaptureImpl:(Unre3DAR3DCaptureImpl*) impl
{
    self = [super init];
    if (self) {
        self.unre3DAR3DCaptureImpl = impl;
        [self commitUnre3DImplInit];
    }
    return self;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self commitUnre3DImplInit];
    }
    return self;
}

- (void) commitUnre3DImplInit
{
    _unre3DScanner = [UnreScannerII new];
    _unre3DScanner.unre3DScannerDelegateH = self;
    _unre3DProcessor = [Unre3DProcessor new];
    _unre3DProcessor.unre3DProcessorDelegateH = self;
}

- (void)setUnre3DAR3DCaptureImplDelegate:(id<Unre3DAR3DCaptureImplDelegate>)unre3DAR3DCaptureImplDelegate
{
    _unre3DAR3DCaptureImplDelegate = unre3DAR3DCaptureImplDelegate;
    self.unre3DScanner.unre3DAR3DCaptureImplDelegate = _unre3DAR3DCaptureImplDelegate;
    self.unre3DProcessor.unre3DAR3DCaptureImplDelegate = _unre3DAR3DCaptureImplDelegate;
}
//////////////////////////// API ///////////////////////
- (BOOL) startPreView:(UIView *)previewUIView
{
    if([_unre3DScanner setPreviewUIView:previewUIView]){
        return [_unre3DScanner startTracking];
    }
    return NO;
}

- (BOOL) stopPreView
{
    return [_unre3DScanner cancel];
}

- (BOOL) startCapture:(Unre3DAR3DCaptureInfo*) unre3DAR3DCaptureInfo;
{
    self.canCreateOBJ = NO;
    return [_unre3DScanner startScanner:unre3DAR3DCaptureInfo];
}

- (BOOL) createOBJ
{
    if(self.canCreateOBJ){
        [self.unre3DProcessor createOBJ:(Unre3DAR3DCaptureInfo*)_unre3DAR3DCaptureImpl.captureAR3DCaptureInfo
        andUnre3DHeadScannerSessionData:self.unre3DScanner.sessionData];
        return YES;
    } else {
        if(_unre3DAR3DCaptureImplDelegate){
            [_unre3DAR3DCaptureImplDelegate notifyCaptureFAIL:Unre3DAR3DFAILHintStartProcessNULL];
        }
    }
    return NO;
}

////////////////////////////////////////////////////////////////////////////////////////////////
- (void) notifyCompleteScanningSuccessfully:(BOOL)completedSuccessfully
{
    if(_unre3DAR3DCaptureImpl){
        self.canCreateOBJ = completedSuccessfully;//此时判断是否可以生成OBJ
        if([_unre3DAR3DCaptureImpl getCurrentCaptureState] == AR3DCAPTURE_STATE_CAPTURE
           && [_unre3DAR3DCaptureImpl setCurrentCaptureState:AR3DCAPTURE_STATE_FILESAVE]){
            if(!completedSuccessfully){
                NSLog(@"Unre3D拍摄失败");
            }
            if(_unre3DAR3DCaptureImplDelegate){
                if(!completedSuccessfully){
                    [_unre3DAR3DCaptureImplDelegate notifyCaptureFAIL:Unre3DAR3DFAILHintCapture];
                }
            }
        }
    }
}

- (void) notifyCompleteProcessingWithMesh:(BOOL) completedSuccessfully
{
    if(_unre3DAR3DCaptureImpl){
        if([_unre3DAR3DCaptureImpl getCurrentCaptureState] == AR3DCAPTURE_STATE_FILESAVE){
            NSLog(@"OBJ 处理完成 %@", (completedSuccessfully?@"SUCCESS" : @"FAIL"));
            self.canCreateOBJ = NO;//s上一次的已经被处理
            if(!completedSuccessfully){
                if(_unre3DAR3DCaptureImplDelegate){
                    [_unre3DAR3DCaptureImplDelegate notifyCaptureFAIL:Unre3DAR3DFAILHintProcess];
                }
            }
            [_unre3DAR3DCaptureImpl notifyCapturefinishH:completedSuccessfully];
//            [self ]
        }
    }
}

@end
/////////////////////////////////////////Unre3DImpl//////////////////////////////////////////////////////


