//
//  UIImage+Haneke.swift
//  Haneke
//
//  Created by Hermes Pique on 8/10/14.
//  Copyright (c) 2014 Haneke. All rights reserved.
//

import UIKit

extension UIImage {

    func hnk_imageByScaling(toSize size: CGSize) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, !hnk_hasAlpha(), 0.0)
        draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return resizedImage!
    }

    func hnk_hasAlpha() -> Bool {
        guard let alphaInfo = self.cgImage?.alphaInfo else { return false }
        switch alphaInfo {
        case .first, .last, .premultipliedFirst, .premultipliedLast, .alphaOnly:
            return true
        case .none, .noneSkipFirst, .noneSkipLast:
            return false
        }
    }
    
    func hnk_data(compressionQuality: Float = 1.0) -> Data! {
        let hasAlpha = self.hnk_hasAlpha()
        let data = hasAlpha ? self.pngData() : self.jpegData(compressionQuality: CGFloat(compressionQuality))
        return data
    }
    
    func hnk_decompressedImage() -> UIImage! {
        let originalImageRef = self.cgImage
        let originalBitmapInfo = originalImageRef?.bitmapInfo
        guard let alphaInfo = originalImageRef?.alphaInfo else { return UIImage() }
        
        // See: http://stackoverflow.com/questions/23723564/which-cgimagealphainfo-should-we-use
        var bitmapInfo = originalBitmapInfo
        switch alphaInfo {
        case .none:
            let rawBitmapInfoWithoutAlpha = (bitmapInfo?.rawValue)! & ~CGBitmapInfo.alphaInfoMask.rawValue
            let rawBitmapInfo = rawBitmapInfoWithoutAlpha | CGImageAlphaInfo.noneSkipFirst.rawValue
            bitmapInfo = CGBitmapInfo(rawValue: rawBitmapInfo)
        case .premultipliedFirst, .premultipliedLast, .noneSkipFirst, .noneSkipLast:
            break
        case .alphaOnly, .last, .first: // Unsupported
            return self
        }
        
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let pixelSize = CGSize(width: self.size.width * self.scale, height: self.size.height * self.scale)
        guard let context = CGContext(data: nil, width: Int(ceil(pixelSize.width)), height: Int(ceil(pixelSize.height)), bitsPerComponent: (originalImageRef?.bitsPerComponent)!, bytesPerRow: 0, space: colorSpace, bitmapInfo: (bitmapInfo?.rawValue)!) else {
            return self
        }

        let imageRect = CGRect(x: 0, y: 0, width: pixelSize.width, height: pixelSize.height)
        UIGraphicsPushContext(context)
        
        // Flip coordinate system. See: http://stackoverflow.com/questions/506622/cgcontextdrawimage-draws-image-upside-down-when-passed-uiimage-cgimage
        context.translateBy(x: 0, y: pixelSize.height)
        context.scaleBy(x: 1.0, y: -1.0)
        
        // UIImage and drawInRect takes into account image orientation, unlike CGContextDrawImage.
        self.draw(in: imageRect)
        UIGraphicsPopContext()
        
        guard let decompressedImageRef = context.makeImage() else {
            return self
        }
        
        let scale = UIScreen.main.scale
        let image = UIImage(cgImage: decompressedImageRef, scale:scale, orientation:UIImage.Orientation.up)
        return image
    }

}
