//
//  PDFDocumentView.m
//  PDFReader
//
//  Created by Dong Li on 12-4-8.
//  Copyright (c) 2013年 __MyCompanyName__. All rights reserved.
//

#import "PDFControlView.h"
#import "PDFTiledView.h"

#define kPDFPageGapX 5
#define kPDFPageGapY 5

@interface PDFControlView (PrivateMethods)
@end

@implementation PDFControlView

@synthesize numberOfPages = _numberOfPages;
@synthesize controlViewDelegate = _controlViewDelegate;

- (id)initWithFrame:(CGRect)frame document:(CGPDFDocumentRef)document {
    if (self = [super initWithFrame:frame]) {
        [self setBackgroundColor:UIColorTexturedBackground];
        [self setShowsVerticalScrollIndicator:NO];
        [self setShowsHorizontalScrollIndicator:NO];
        [self setBounces:NO];
        [self setAlwaysBounceHorizontal:NO];
        [self setAlwaysBounceVertical:NO];
        [self setBouncesZoom:YES];
        [self setAutoresizingMask:UIFlxSize];
        
        _layoutView = [[UIView alloc] initWithFrame:CGRectZero];
        [_layoutView setBackgroundColor:UIColorClear];
        [self addSubview:_layoutView];
        
        _PDFDocument = CGPDFDocumentRetain(document);
        _numberOfPages = CGPDFDocumentGetNumberOfPages(_PDFDocument);
        _pageInfos = (PDFPageInfo *)malloc(sizeof(PDFPageInfo) * _numberOfPages);
        
        for (NSInteger i = 0; i < _numberOfPages; ++ i) {
            CGPDFPageRef page = CGPDFDocumentGetPage(_PDFDocument, (i + 1));
            const CGFloat rotate = (CGFloat)CGPDFPageGetRotationAngle(page) * CGRadianPerDegree;
            const CGRect cropRect = CGRectApplyAffineTransform(CGPDFPageGetBoxRect(page, kCGPDFCropBox), CGAffineTransformMakeRotation(rotate));
            PDFTiledView *pageView = [[PDFTiledView alloc] initWithFrame:CGRectZero document:_PDFDocument page:page];
            
            _pageInfos[i].page = page;
            _pageInfos[i].rect = cropRect;
            _pageInfos[i].rotate = rotate;
            _pageInfos[i].view = pageView;
            
            [_layoutView addSubview:pageView];
            
            }
    }
    return self;
}

- (void)dealloc {
    if (_PDFDocument) {
        CGPDFDocumentRelease(_PDFDocument);
    }
    if (_pageInfos) {
        free(_pageInfos);
    }
}

- (void)calculatePageWithViewSize:(const CGSize)viewSize contentSize:(const CGSize)contentSize contentOffset:(const CGPoint)contentOffset {
    const CGFloat centerOffsetY = contentOffset.y + viewSize.height / 2.f;
    const CGFloat ratio = contentOffset.y / (contentSize.height - viewSize.height);
    
    if (1.f > ratio) {
        NSInteger i, dstIndex;
        const NSInteger assumedIndex = (CGFloat)_numberOfPages * ratio;
        CGRect pageFrame = [_pageInfos[assumedIndex].view frame];
        
        if (centerOffsetY < pageFrame.origin.y) {
            dstIndex = 0;
            for (i = assumedIndex - 1; i > dstIndex; -- i) {
                pageFrame = [_pageInfos[i].view frame];
                if (centerOffsetY >= pageFrame.origin.y) {
                    dstIndex = i;
                    break;
                }
            }
        } else if (centerOffsetY > (pageFrame.origin.y + pageFrame.size.height)) {
            dstIndex = _numberOfPages - 1;
            for (i = assumedIndex + 1; i < dstIndex; ++ i) {
                pageFrame = [_pageInfos[i].view frame];
                if (centerOffsetY <= (pageFrame.origin.y + pageFrame.size.height)) {
                    dstIndex = i;
                    break;
                }
            }
        } else {
            dstIndex = assumedIndex;
        }
        
        [_controlViewDelegate controlView:self didScrollToPage:(dstIndex + 1) ratio:ratio];
    }
}

- (void)layoutSubviews {
    const CGSize viewSize = self.bounds.size;
    CGRect layoutFrame;
    
    if (fabs(_initialSize.width - viewSize.width) >= 0.5f) {
        [self setZoomScale:1.f];
        
        const CGSize oldContentSize = [self contentSize];
        CGPoint contentOffset = [self contentOffset];
        const CGFloat pageWidth = viewSize.width - kPDFPageGapX * 2;
        CGFloat contentHeight = kPDFPageGapY;
        
        for (NSInteger i = 0; i < _numberOfPages; ++ i) {
            const CGRect rect = _pageInfos[i].rect;
            const CGFloat scale = pageWidth / rect.size.width;
            const CGFloat pageHeight = (NSInteger)(scale * rect.size.height + 0.5);
            PDFTiledView *pageView = _pageInfos[i].view;
            const CGRect pageFrame = { kPDFPageGapX, contentHeight, pageWidth, pageHeight };
            
            [pageView setFrame:pageFrame];
            [pageView setScale:scale rotate:_pageInfos[i].rotate offset:rect.origin];
            contentHeight += (pageHeight + kPDFPageGapY);
        }
        
        _initialSize.width = viewSize.width;
        _initialSize.height = contentHeight;
        contentOffset.x = 0.f;
        /*if (oldContentSize.width >= 1.f) {
            contentOffset.x = (NSInteger)(contentOffset.x * _initialSize.width / oldContentSize.width + 0.5);
        }*/
        
        if (oldContentSize.height >= 1.f) {
            contentOffset.y = (NSInteger)(contentOffset.y * _initialSize.height / oldContentSize.height + 0.5);
        }
        
        layoutFrame.origin = CGPointZero;
        layoutFrame.size = _initialSize;
        
        [self setContentSize:_initialSize];
        [self setContentOffset:contentOffset];
        [self calculatePageWithViewSize:viewSize contentSize:_initialSize contentOffset:contentOffset];
        
    } else {
        
        layoutFrame = [_layoutView frame];
    }
    
    // center horizontally
    if (layoutFrame.size.width < viewSize.width) {
        layoutFrame.origin.x = (viewSize.width - layoutFrame.size.width) / 2;
    } else {
        layoutFrame.origin.x = 0;
    }
    
    // center vertically
    if (layoutFrame.size.height < viewSize.height) {
        layoutFrame.origin.y = (viewSize.height - layoutFrame.size.height) / 2;
    } else {
        layoutFrame.origin.y = 0;
    }
    [_layoutView setFrame:layoutFrame];
}

#pragma mark - UIScrollViewDelegate

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return _layoutView;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    const CGSize viewSize = self.bounds.size;
    const CGSize contentSize = [self contentSize];
    CGPoint contentOffset = [self contentOffset];
    
    [self calculatePageWithViewSize:viewSize contentSize:contentSize contentOffset:contentOffset];
}

@end
