//
//  NXWhiteboardElement.h
//  NXKit
//
//  Created by 徐家骏 on 2020/6/28.
//  Copyright © 2020 徐家骏. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
#import <CocoaSecurity/Base64.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(int, NXWhiteboardElementType)
{
    NXWhiteboardElementTypeDoodle           = 1,  //涂鸦笔画，自由曲线
    NXWhiteboardElementTypeLaser            = 2,  //这个比较特殊，从来都不需要保存起来
    
    NXWhiteboardElementTypeShapeLine          = 10,  //形状，直线，矩形，圆，椭圆，三角形，多边形之类
    NXWhiteboardElementTypeShapePolyLine      = 11,  //折线，画的过程中稍作停顿即可
    NXWhiteboardElementTypeShapeFillPolyLine  = 12,  //折线，画的过程中稍作停顿即可，但最后封闭并填色，如果不能封闭则不填色，能否封闭的定义是最后点与初始点的距离
    
    NXWhiteboardElementTypeShapeRect             = 20,
    NXWhiteboardElementTypeShapeFillRect         = 21,
    NXWhiteboardElementTypeShapeRoundedRect      = 22,
    NXWhiteboardElementTypeShapeFillRoundedRect  = 23,
    
    NXWhiteboardElementTypeShapeCircle      = 30,
    NXWhiteboardElementTypeShapeFillCircle  = 31,
    NXWhiteboardElementTypeShapeOval        = 32,
    NXWhiteboardElementTypeShapeFillOval    = 33,
    
    //以上是BezierPath
    NXWhiteboardElementTypeImage            = 100,  //图片
    NXWhiteboardElementTypeText             = 110,  //文本
    
    //组合element
    NXWhiteboardElementTypeCombination      = 200,  //组合类，可以包含所有类型的元素
    
    NXWhiteboardElementTypeEraser           = 255,  //像素橡皮擦，叠加与其他元素上面，擦除相应部分
};

typedef NS_ENUM(int, NXWhiteboardElementStatus)
{
    NXWhiteboardElementStatusCreated   = 1,  //正常的元素状态，已创建或者编辑完成
    NXWhiteboardElementStatusCreating  = 2,  //元素正在创建过程中，比如画一个笔画的中间过程
    NXWhiteboardElementStatusEditing   = 3,  //元素正在被编辑，比如被移动位置等操作，文本比较特殊，第一次创建文本，输入的时候是creating，后续编辑文本框输入的时候是editing
    NXWhiteboardElementStatusDeleted   = 4,  //元素已经被删除，如果删除动作undo了，那么回到created状态
//    NXWhiteboardElementStatusLocked    = 5,  //元素被锁定，解除锁定的时候回到正常状态created
    NXWhiteboardElementStatusEdited    = 6,  //大部分元素的编辑，会copy一个副本出来，这个时候之前的版本被设置为edited，copy出来的副本在编辑过程中是editing，编辑完成进入正常状态created
    NXWhiteboardElementStatusUndoed    = 7,  //指令被undo，这个指令涉及的元素会回到用上个版本，但为了redo的时候能够重做恢复，这个元素被置为undoed状态，redo的时候恢复created即可。
    
    NXWhiteboardElementStatusConfilict = 99, //这个是并发冲突的遗留，不渲染。
};

typedef NS_ENUM(int, NXWhiteboardElementLockStatus)
{
    NXWhiteboardElementLockStatusNone        = 0,  //不锁定
    NXWhiteboardElementLockStatusLocked      = 1,  //正常的锁定
//    NXWhiteboardElementLockStatusLockedMove  = 2,  //比如不让移动
//    NXWhiteboardElementLockStatusLockedEdit  = 3,  //比如不让编辑内容，比如文本元素
};

typedef NS_ENUM(int, NXWhiteboardElementSelect)
{
    NXWhiteboardElementSelected         = 1,  //bit0, 这个是本地状态，被自己选中，目前的设计选中是本地状态不同步给他人。在选中状态，但没有changing的时候，需要显示action菜单
    NXWhiteboardElementChangingBySelf   = 2,  //bit1, 选中后如果有移动，文本编辑等在进行中，这个状态同步给他人，但是否要做控制，后续待定
    NXWhiteboardElementChangingByOthers = 4,  //bit2, 他人在changing这个元素，这里要跟self分开的原因是我们逻辑上需要知道自己什么时候开始changing，如果他人同时操作，不分开会混乱。
};

@class NXWhiteboard;

@interface NXWhiteboardElement : NSObject<NSCoding>

@property (nonatomic, weak)     NXWhiteboard  *whiteboard; //持有一个弱引用，render时需要用到

@property (nonatomic)           int      type; //笔画，图形，图片等
@property (nonatomic)           NXWhiteboardElementStatus      status; //当前状态，已创建，在增补，在编辑，已删除。
@property (nonatomic)           int      lockStatus; //当前锁定状态，0不锁定
@property (nonatomic)           int      wbid; //属于哪块画板
@property (nonatomic)           int      eid; //自己的element id
@property (nonatomic)           int64_t  uid; //那个用户画的，可用于按用户全部撤销，为0的话是自己画的 ->改为自己的uid也要设置，不然erase和sync都比较麻烦
@property (nonatomic)           int64_t  timestamp; //创建时间
@property (nonatomic)           CGPoint  offset; //用于元素移动的时候记住偏移位置
@property (nonatomic)           CGRect   rect; //这个元素的外围矩形，可用于选中等操作
@property (nonatomic)           int      color;
@property (nonatomic)           int      size;
@property (nonatomic)           int      pattern;  //线条的pattern

/// 如果被初始化，说明送过来的压感数据在这里，不在data里。
@property (nonatomic)           NSMutableArray<NSNumber *> *pressures;

@property (nonatomic, strong)   NSMutableData *data; //涂鸦的点，图片的数据等

@property (nonatomic)           int      selected; //如果是选中状态，则需要画外虚线边框, //这个改为int，第0位表示是否选中，第1位表示当前是否在变动如移动，文字改动。
@property (nonatomic)           int64_t  selectedUid; //是谁选中的。

//用transform来控制元素的平移，缩放和旋转
@property (nonatomic)           CGAffineTransform   transform;

//组合元素的属性
@property (nonatomic)           int              combineAttribute;
@property (nonatomic, strong)   NSMutableArray  *subElements;

//这时临时数据，都本地计算时用，不需要序列化和同步
@property (nonatomic)           CGPoint  prevPoint; //以下两个是在绘图刷新时临时需要用到的
@property (nonatomic)           CGPoint  prevTouchPoint;
@property (nonatomic)           CGRect   currentSliceRect; //这个是为了在active的时候，减少刷新区域，减少cpu开销
@property (nonatomic)           CGRect   rectWithOffset; //这个元素的外围矩形，根据offset调整过，可用于选中，渲染等操作
@property (nonatomic, strong, nullable)   UIImage   *image; //对于图片元素和组合元素，这里是一张cache的图片
@property (nonatomic)           BOOL     hasPendingRequestForSyncData;
@property (nonatomic)           int      numRequestForSyncData;
@property (nonatomic)           BOOL     isFirstResponder;

- (instancetype)initWithData:(NSData *)data;
- (instancetype)initWithJson:(NSDictionary *)json;
- (NSData *)toData;
- (NSData *)toGroupElementData;
- (NSDictionary *)toJson;
- (UIBezierPath *)pathFor:(CGRect)rect;
- (NSArray <UIBezierPath *>*)subPathForRect:(CGRect) rect;
- (void)renderToCurrentContextInRect:(CGRect)rect;
- (void)renderToCurrentContextInRectWithOnlyRect:(CGRect)rect; //被选中的元素如果被遮挡，那么只渲染一个边框
- (BOOL)isActive;
- (BOOL)isSelected;
- (BOOL)isChangingBySelf;
- (BOOL)isChangingByOthers;
- (void)setSelected:(BOOL)selected;
- (void)setChangingBySelf:(BOOL)changing;
- (void)setChangingByOthers:(BOOL)changing;


- (NXWhiteboardElement *) clone;

- (void)addPressure:(CGFloat)pressure inData:(BOOL)inData;

@end

NS_ASSUME_NONNULL_END

/*
白板元素
针对每块白板上的刷新序列，在每块白板上保存

元素基本数据：
0. 类型：
1. offset，移动的时候直接改这个
2. eid：元素的唯一标识id
3. wid：元素所属于的白板id
4. 时间戳
5. 坐标都用浮点数？相对于白板尺寸的相对量
6. rect

元素类型：
1. 涂鸦笔画，points列表，颜色，size，pattern
2. 图片，data，
3. Shape
4. Text
5.

*/
