//
//  KMWatermarkModel.swift
//  PDF Master
//
//  Created by tangchao on 2022/12/19.
//

import Cocoa

@objcMembers class KMWatermarkModel: KMWatermarkAdjectiveBaseModel {
    var text: String = ""
    var image: NSImage!
    var imagePath: String!
    
    var textAligement: NSTextAlignment = .left
    
    var rotation: CGFloat = 0.0
    var opacity: CGFloat = 0.0
    
    var scale: CGFloat = 0.0
    
    /**
     (Top:0 Middle:1 Bottom:2)
     */
    var verticalMode: Int = 1
    var verticalSpace: CGFloat = 0.0
    /**
     (Left:0 Middle:1 Right:2)
     */
    var horizontalMode: Int = 1
    var horizontalSpace: CGFloat = 0.0
    
    var tileHorizontalSpace: CGFloat = 60
    var tileVerticalSpace: CGFloat = 60
    var pagesString: String!
    
    var isFront: Bool = true
    var isTilePage: Bool = false
    
    var tag: String!
    
    var creatTemplateDate: String!
    
    var watermark: CPDFWatermark!
    
    var watermarkID: String!
    
    override func copy() -> Any {
        let model = KMWatermarkModel()
        model.text = self.text
        model.image = self.image
        model.imagePath = self.imagePath
        
        model.textColor = self.textColor
        model.textFont = self.textFont
        
        model.rotation = self.rotation
        model.opacity = self.opacity
        
        model.scale = self.scale
        
        model.verticalMode = self.verticalMode
        model.verticalSpace = self.verticalSpace
        model.horizontalMode = self.horizontalMode
        model.horizontalSpace = self.horizontalSpace
        
        model.tileHorizontalSpace = self.tileHorizontalSpace
        model.tileVerticalSpace = self.tileVerticalSpace
        model.pagesString = self.pagesString
        
        model.isFront = self.isFront
        model.isTilePage = self.isTilePage
        
        model.tag = self.tag
        
        model.pageRangeType = self.pageRangeType
        
        model.creatTemplateDate = self.creatTemplateDate
        
        model.watermark = self.watermark
        
        model.watermarkID = self.watermarkID
        
        return model
    }
    
    func updateData(document: CPDFDocument) {
        if (self.watermark == nil) {
            var scale: CGFloat = self.scale
            if (!self.text.isEmpty) {
                self.watermark = CPDFWatermark(document: document, type: .text)
                self.watermark.text = self.text
                self.watermark.textColor = self.getTextColor()
                scale = self.getTextFont().pointSize / 24.0
            } else {
                self.watermark = CPDFWatermark(document: document, type: .image)
                self.watermark.image = self.image
            }
        } else {
            if (!self.text.isEmpty) {
                self.watermark.text = self.text
                self.watermark.textColor = self.getTextColor()
                scale = self.getTextFont().pointSize / 24.0
            } else {
                self.watermark.image = self.image
            }
        }
        
        self.watermark.scale = scale
        self.watermark.rotation = -self.rotation
        self.watermark.opacity = self.opacity
        self.watermark.tx = self.horizontalSpace
        self.watermark.ty = self.verticalSpace
        self.watermark.isFront = self.isFront
        self.watermark.pageString = self.pagesString
        self.watermark.isTilePage = self.isTilePage
        self.watermark.horizontalSpacing = self.tileHorizontalSpace / scale
        self.watermark.verticalSpacing = self.tileVerticalSpace / scale
        if (self.verticalMode == 0) {
            self.watermark.verticalPosition = .top
        } else if (self.verticalMode == 1) {
            self.watermark.verticalPosition = .center
        } else if (self.verticalMode == 2) {
            self.watermark.verticalPosition = .bottom
        }
        
        if (self.horizontalMode == 0) {
            self.watermark.horizontalPosition = .left
        } else if (self.horizontalMode == 1) {
            self.watermark.horizontalPosition = .center
        } else if (self.horizontalMode == 2) {
            self.watermark.horizontalPosition = .right
        }
    }
    
    func drawImage(rect: CGRect) -> NSImage {
        var size: NSSize = NSZeroSize
        var drawRect: CGRect = NSMakeRect(0, 0, 128, 160)
        if (!self.text.isEmpty) {
            var font = NSFont.systemFont(ofSize: 48)
            if (self.isTilePage) {
                font = self.getTextFont()
            }
            
            var style = NSMutableParagraphStyle()
            style.alignment = self.textAligement
            style.lineBreakMode = .byCharWrapping
            let dictionary = [NSAttributedString.Key.paragraphStyle : style, NSAttributedString.Key.font : font]
            size = self.text.boundingRect(with: NSSize(width: 1000, height: 1000), options: NSString.DrawingOptions(rawValue: 3), attributes: dictionary).size
        } else if (self.image != nil) {
            size = self.image.size
            size.width = size.width * self.scale
            size.height = size.height * self.scale
        }
        
        let radian = self.rotation * (Double.pi/180.0)
        let t: CGAffineTransform =  CGAffineTransform(rotationAngle: radian)
        if (!self.isTilePage) {
            drawRect = NSMakeRect(0, 0, size.width+40, size.height+40).applying(t);
        }
        
        let image = NSImage(size: drawRect.size)
        image.lockFocus()
        NSGraphicsContext.current?.imageInterpolation = .high
        
        NSGraphicsContext.saveGraphicsState()
        NSColor.clear.set()
        drawRect.fill()
        NSGraphicsContext.restoreGraphicsState()
        
        let context: CGContext = NSGraphicsContext.current!.cgContext
        
        let imageSize: NSSize = NSMakeSize(drawRect.size.width, drawRect.size.height)
        
        if (context != nil) {
            NSGraphicsContext.current = NSGraphicsContext(cgContext: context, flipped: false)
        }
        
        NSGraphicsContext.saveGraphicsState()
        if (!self.text.isEmpty) {
            var font = NSFont.systemFont(ofSize: 48)
            if (self.isTilePage) {
                font = self.getTextFont()
            }
            
            var color = NSColor.black
            if (self.textColor != nil) {
                color = self.getTextColor()
            }
            
            var red: CGFloat = 0
            var green: CGFloat = 0
            var blue: CGFloat = 0
            color.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil)
            color = NSColor(calibratedRed: red, green: green, blue: blue, alpha: 1.0)
            
            var size = NSZeroSize
            let style = NSMutableParagraphStyle()
            style.alignment = self.textAligement
            style.lineBreakMode = .byCharWrapping
            let dictionary = [NSAttributedString.Key.paragraphStyle : style, NSAttributedString.Key.foregroundColor : color, NSAttributedString.Key.font : font]
            size = self.text.boundingRect(with: NSSize(width: 1000, height: 1000), options: NSString.DrawingOptions(rawValue: 3), attributes: dictionary).size
            
            let radian: CGFloat = self.rotation * (Double.pi / 180.0)
            let t: CGAffineTransform = CGAffineTransform(rotationAngle: radian)
            var textRect = NSMakeRect(0, 0, size.width, size.height).applying(t)
            if (self.isTilePage) {
                let width = sqrt(image.size.height * image.size.height + image.size.width * image.size.width)
                let newRect = NSMakeRect(-(width - image.size.width)/2, -(width - image.size.height)/2, width, width)
                let new_w = NSWidth(newRect)
                let new_h = NSHeight(newRect)
                
                context.translateBy(x: image.size.width/2,y: image.size.height/2);
                context.concatenate(t);
                context.translateBy(x: -(image.size.width/2),  y: -(image.size.height/2));
                
                let verticalWidth: CGFloat = size.width + self.tileHorizontalSpace/3.0
                let horizontalHeight: CGFloat = size.height + self.tileVerticalSpace/3.0
                let line: Int = Int(((new_h - self.tileHorizontalSpace/3.0)/horizontalHeight) + 1)
                let row: Int = Int((new_w - self.tileVerticalSpace/3.0) / verticalWidth + 1)
                let point = NSPoint(x: image.size.width/2 - size.width/2+self.horizontalSpace/3.0, y: image.size.height/2 - size.height/2+self.verticalSpace/3.0)
                for i in 0 ..< line {
                    for j in 0 ..< row {
                        self.text.draw(in: NSRect(x: point.x+CGFloat(j)*verticalWidth, y: point.y+CGFloat(i)*horizontalHeight, width: size.width, height: size.height), withAttributes: dictionary)
                    }
                }
                
                for i in 1 ..< line {
                    for j in 0 ..< row {
                        self.text.draw(in: NSRect(x: point.x+CGFloat(j)*verticalWidth, y: point.y-CGFloat(i)*horizontalHeight, width: size.width, height: size.height), withAttributes: dictionary)
                    }
                }
                
                for i in 0 ..< line {
                    for j in 1 ..< row {
                        self.text.draw(in: NSRect(x: point.x-CGFloat(j)*verticalWidth, y: point.y+CGFloat(i)*horizontalHeight, width: size.width, height: size.height), withAttributes: dictionary)
                    }
                }
                
                for i in 1 ..< line {
                    for j in 1 ..< row {
                        self.text.draw(in: NSRect(x: point.x-CGFloat(j)*verticalWidth, y: point.y-CGFloat(i)*horizontalHeight, width: size.width, height: size.height), withAttributes: dictionary)
                    }
                }
            } else {
                if (self.verticalMode == 0) {
                    textRect.origin.y = imageSize.height-textRect.size.height
                } else if (self.verticalMode == 1) {
                    textRect.origin.y = (imageSize.height-textRect.size.height) * 0.5
                } else {
                    textRect.origin.y = 0
                }
                
                if (self.horizontalMode == 0) {
                    textRect.origin.x = 0
                } else if (self.horizontalMode == 1) {
                    textRect.origin.x = (imageSize.width-textRect.size.width) * 0.5
                } else {
                    textRect.origin.x = imageSize.width-textRect.size.width
                }
                
                textRect.origin.x += self.horizontalSpace
                textRect.origin.y += self.verticalSpace
                
                let contextCenter = CGPoint(x: textRect.midX, y: textRect.midY)
                context.translateBy(x: contextCenter.x, y: contextCenter.y)
                context.rotate(by: radian)
                context.translateBy(x: -contextCenter.x, y: -contextCenter.y)
                
                let testRect = NSMakeRect(textRect.origin.x+(textRect.size.width-size.width)/2.0,
                                          textRect.origin.y+(textRect.size.height-size.height)/2.0,
                      size.width, size.height)
                self.text.draw(in: NSMakeRect(textRect.origin.x+(textRect.size.width-size.width)/2.0,
                                                             textRect.origin.y+(textRect.size.height-size.height)/2.0,
                                         size.width, size.height), withAttributes: dictionary)
            }
        } else if (self.image != nil) {
            var size = self.image.size
            size.width *= self.scale
            size.height *= self.scale
            
            let width: CGFloat = sqrt(image.size.height * image.size.height + image.size.width * image.size.width)
            let newRect = NSMakeRect(-(width - image.size.width)/2, -(width - image.size.height)/2, width, width)
            let new_w = newRect.size.width
            let new_h = newRect.size.height
            let radian: CGFloat = self.rotation * (Double.pi / 180.0)
            let t: CGAffineTransform = CGAffineTransform(rotationAngle: radian)
            if (self.isTilePage) {
                context.translateBy(x: image.size.width/2,y: image.size.height/2)
                context.concatenate(t)
                context.translateBy(x: -(image.size.width/2),  y: -(image.size.height/2))
                
                let verticalWidth: CGFloat = size.width + self.tileHorizontalSpace * self.scale
                let horizontalHeight: CGFloat = size.height + self.tileVerticalSpace * self.scale
                let line: Int = Int((new_h - self.tileVerticalSpace * self.scale) / horizontalHeight + 1)
                let row: Int = Int((new_w - self.tileHorizontalSpace * self.scale) / verticalWidth + 1)
                let point = NSPoint(x: image.size.width/2 - size.width/2+self.horizontalSpace*self.scale, y: image.size.height/2 - size.height/2+self.verticalSpace * self.scale)
                for i in 0 ..< (line/2+1) {
                    for j in 0 ..< row {
                        let area = CGRect(x: point.x  + CGFloat(j) * verticalWidth, y: point.y + CGFloat(i)*horizontalHeight, width: size.width, height: size.height)
                        self.image.draw(in: area, from: NSZeroRect, operation: .overlay, fraction: self.opacity)
                    }
                }
                
                for i in 1 ..< (line/2+1) {
                    for j in 0 ..< row {
                        let area = CGRect(x: point.x  + CGFloat(j) * verticalWidth, y: point.y - CGFloat(i)*horizontalHeight, width: size.width, height: size.height)
                        self.image.draw(in: area, from: NSZeroRect, operation: .overlay, fraction: self.opacity)
                    }
                }
                
                for i in 0 ..< (line/2+1) {
                    for j in 1 ..< row {
                        let area = CGRect(x: point.x  - CGFloat(j) * verticalWidth, y: point.y + CGFloat(i)*horizontalHeight, width: size.width, height: size.height)
                        self.image.draw(in: area, from: NSZeroRect, operation: .overlay, fraction: self.opacity)
                    }
                }
                
                for i in 1 ..< (line/2+1) {
                    for j in 1 ..< row {
                        let area = CGRect(x: point.x  - CGFloat(j) * verticalWidth, y: point.y - CGFloat(i)*horizontalHeight, width: size.width, height: size.height)
                        self.image.draw(in: area, from: NSZeroRect, operation: .overlay, fraction: self.opacity)
                    }
                }
            } else {
                var size = self.image.size
                size.width *= self.scale
                size.height *= self.scale
                
                let radian: CGFloat = self.rotation * (Double.pi / 180.0)
                let t: CGAffineTransform = CGAffineTransform(rotationAngle: radian)
                var imageRect = NSMakeRect(0, 0, size.width, size.height).applying(t)
                
                if (self.verticalMode == 0) {
                    imageRect.origin.y = imageSize.height-imageRect.size.height
                } else if (self.verticalMode == 1) {
                    imageRect.origin.y = (imageSize.height-imageRect.size.height) * 0.5
                } else {
                    imageRect.origin.y = 0
                }
                
                if (self.horizontalMode == 0) {
                    imageRect.origin.x = 0
                } else if (self.horizontalMode == 1) {
                    imageRect.origin.x = (imageSize.width-imageRect.size.width) * 0.5
                } else {
                    imageRect.origin.x = imageSize.width-imageRect.size.width
                }
                
                
                let contextCenter = CGPoint(x: rect.midX, y: rect.midY)
                context.translateBy(x: contextCenter.x, y: contextCenter.y)
                context.rotate(by: radian)
                context.translateBy(x: -contextCenter.x, y: -contextCenter.y)
                
                let finalRect = NSMakeRect(imageRect.origin.x+(imageRect.size.width-size.width)/2.0,
                                           imageRect.origin.y+(imageRect.size.height-size.height)/2.0,
                                           size.width, size.height)
                
                self.image.draw(in: finalRect, from: NSZeroRect, operation: .overlay, fraction: self.opacity)
            }
        }
        
        NSGraphicsContext.restoreGraphicsState()
        
        NSGraphicsContext.current?.imageInterpolation = .default
        
        image.unlockFocus()
        
        return image
    }
}