#import "CPTPieChartPlugin.h"

@implementation CPTPieChartPlugIn

/*
 * NOTE: It seems that QC plugins don't inherit dynamic input ports which is
 * why all of the accessor declarations are duplicated here
 */

/*
 * Accessor for the output image
 */
@dynamic outputImage;

/*
 * Dynamic accessors for the static PlugIn inputs
 */
@dynamic inputPixelsWide, inputPixelsHigh;
@dynamic inputAxisLineWidth, inputAxisColor;
@dynamic inputPlotAreaColor, inputBorderColor, inputBorderWidth;
@dynamic inputLabelColor;

/*
 * Pie chart special accessors
 */
@dynamic inputPieRadius, inputSliceLabelOffset, inputStartAngle, inputSliceDirection;

+(nonnull NSDictionary<NSString *, NSString *> *)attributes
{
    return @{
        QCPlugInAttributeNameKey: @"Core Plot Pie Chart",
        QCPlugInAttributeDescriptionKey: @"Pie chart"
    };
}

-(double)inputXMax
{
    return 1.0;
}

-(double)inputXMin
{
    return -1.0;
}

-(double)inputYMax
{
    return 1.0;
}

-(double)inputYMin
{
    return -1.0;
}

// Pie charts only support one layer so we override the createViewController method (to hide the number of charts button)

-(nullable QCPlugInViewController *)createViewController
{
    return nil;
}

+(nonnull CPTStringArray *)sortedPropertyPortKeys
{
    CPTStringArray *pieChartPropertyPortKeys = @[@"inputPieRadius", @"inputSliceLabelOffset", @"inputStartAngle", @"inputSliceDirection", @"inputBorderColor", @"inputBorderWidth"];

    return [[super sortedPropertyPortKeys] arrayByAddingObjectsFromArray:pieChartPropertyPortKeys];
}

+(nullable CPTDictionary *)attributesForPropertyPortWithKey:(nullable NSString *)key
{
    // A few additional ports for the pie chart type ...
    if ( [key isEqualToString:@"inputPieRadius"] ) {
        return @{
            QCPortAttributeNameKey: @"Pie Radius",
            QCPortAttributeMinimumValueKey: @0.0,
            QCPortAttributeDefaultValueKey: @0.75
        };
    }
    else if ( [key isEqualToString:@"inputSliceLabelOffset"] ) {
        return @{
            QCPortAttributeNameKey: @"Label Offset",
            QCPortAttributeDefaultValueKey: @20.0
        };
    }
    else if ( [key isEqualToString:@"inputStartAngle"] ) {
        return @{
            QCPortAttributeNameKey: @"Start Angle",
            QCPortAttributeDefaultValueKey: @0.0
        };
    }
    else if ( [key isEqualToString:@"inputSliceDirection"] ) {
        return @{
            QCPortAttributeNameKey: @"Slice Direction",
            QCPortAttributeMaximumValueKey: @1,
            QCPortAttributeMenuItemsKey: @[@"Clockwise", @"Counter-Clockwise"],
            QCPortAttributeDefaultValueKey: @0
        };
    }
    else if ( [key isEqualToString:@"inputBorderWidth"] ) {
        return @{
            QCPortAttributeNameKey: @"Border Width",
            QCPortAttributeMinimumValueKey: @0.0,
            QCPortAttributeDefaultValueKey: @1.0
        };
    }
    else if ( [key isEqualToString:@"inputBorderColor"] ) {
        CGColorRef grayColor  = CGColorCreateGenericGray(0.0, 1.0);
        CPTDictionary *result = @{
                                    QCPortAttributeNameKey: @"Border Color",
                                    QCPortAttributeDefaultValueKey: (id)CFBridgingRelease(grayColor)
        };
        return result;
    }
    else if ( [key isEqualToString:@"inputLabelColor"] ) {
        CGColorRef grayColor  = CGColorCreateGenericGray(1.0, 1.0);
        CPTDictionary *result = @{
                                    QCPortAttributeNameKey: @"Label Color",
                                    QCPortAttributeDefaultValueKey: (id)CFBridgingRelease(grayColor)
        };
        return result;
    }
    else {
        return [super attributesForPropertyPortWithKey:key];
    }
}

-(void)addPlotWithIndex:(NSUInteger)index
{
    if ( index == 0 ) {
        [self addInputPortWithType:QCPortTypeStructure
                            forKey:[NSString stringWithFormat:@"plotNumbers%lu", (unsigned long)index]
                    withAttributes:@{ QCPortAttributeNameKey: [NSString stringWithFormat:@"Data Values %u", (unsigned)(index + 1)],
                                      QCPortAttributeTypeKey: QCPortTypeStructure }
        ];

        [self addInputPortWithType:QCPortTypeStructure
                            forKey:[NSString stringWithFormat:@"plotLabels%lu", (unsigned long)index]
                    withAttributes:@{ QCPortAttributeNameKey: [NSString stringWithFormat:@"Data Labels %lu", (unsigned long)(index + 1)],
                                      QCPortAttributeTypeKey: QCPortTypeStructure }
        ];

        // TODO: add support for used defined fill colors.  As of now we use a single color
        // multiplied against the 'default' pie chart colors
        CGColorRef grayColor = CGColorCreateGenericGray(1.0, 1.0);
        [self addInputPortWithType:QCPortTypeColor
                            forKey:[NSString stringWithFormat:@"plotFillColor%lu", (unsigned long)index]
                    withAttributes:@{ QCPortAttributeNameKey: [NSString stringWithFormat:@"Primary Fill Color %lu", (unsigned long)(index + 1)],
                                      QCPortAttributeTypeKey: QCPortTypeColor,
                                      QCPortAttributeDefaultValueKey: (id)CFBridgingRelease(grayColor) }
        ];

        // Add the new plot to the graph
        CPTPieChart *pieChart = [[CPTPieChart alloc] init];
        pieChart.identifier = [NSString stringWithFormat:@"Pie Chart %lu", (unsigned long)(index + 1)];
        pieChart.dataSource = self;

        [self.graph addPlot:pieChart];
    }
}

#pragma mark -
#pragma mark Graph configuration

-(void)createGraph
{
    if ( !self.graph ) {
        // Create graph from theme
        CPTTheme *theme = [CPTTheme themeNamed:kCPTPlainWhiteTheme];
        self.graph = (CPTXYGraph *)[theme newGraph];

        self.graph.axisSet = nil;
    }
}

-(BOOL)configureAxis
{
    // We use no axis for the pie chart
    self.graph.axisSet = nil;

    self.graph.plotAreaFrame.plotArea.borderLineStyle = nil;

    return YES;
}

-(BOOL)configurePlots
{
    // Configure the pie chart
    for ( CPTPieChart *pieChart in [self.graph allPlots] ) {
        pieChart.plotArea.borderLineStyle = nil;

        pieChart.pieRadius      = self.inputPieRadius * MIN(self.inputPixelsWide, self.inputPixelsHigh) / 2.0;
        pieChart.labelOffset    = self.inputSliceLabelOffset;
        pieChart.startAngle     = self.inputStartAngle * M_PI / 180.0; // QC typically works in degrees
        pieChart.centerAnchor   = CGPointMake(0.5, 0.5);
        pieChart.sliceDirection = (self.inputSliceDirection == 0) ? CPTPieDirectionClockwise : CPTPieDirectionCounterClockwise;

        if ( self.inputBorderWidth > 0.0 ) {
            CPTMutableLineStyle *borderLineStyle = [CPTMutableLineStyle lineStyle];
            borderLineStyle.lineWidth = self.inputBorderWidth;
            borderLineStyle.lineColor = [CPTColor colorWithCGColor:self.inputBorderColor];
            borderLineStyle.lineCap   = kCGLineCapSquare;
            borderLineStyle.lineJoin  = kCGLineJoinBevel;
            pieChart.borderLineStyle  = borderLineStyle;
        }
        else {
            pieChart.borderLineStyle = nil;
        }

        [pieChart reloadData];
    }

    return YES;
}

#pragma mark -
#pragma mark Data source methods

-(NSUInteger)numberOfRecordsForPlot:(nonnull CPTPlot *)plot
{
    NSUInteger plotIndex = [[self.graph allPlots] indexOfObject:plot];
    NSString *key        = [NSString stringWithFormat:@"plotNumbers%lu", (unsigned long)plotIndex];

    return [[self valueForInputKey:key] count];
}

-(nullable id)numberForPlot:(nonnull CPTPlot *)plot field:(NSUInteger __unused)fieldEnum recordIndex:(NSUInteger)index
{
    NSUInteger plotIndex = [[self.graph allPlots] indexOfObject:plot];
    NSString *key        = [NSString stringWithFormat:@"plotNumbers%lu", (unsigned long)plotIndex];

    CPTDictionary *dict = [self valueForInputKey:key];

    if ( dict ) {
        return [NSDecimalNumber decimalNumberWithString:[dict[[NSString stringWithFormat:@"%lu", (unsigned long)index]] stringValue]];
    }
    else {
        return nil;
    }
}

-(nullable CPTFill *)sliceFillForPieChart:(nonnull CPTPieChart *__unused)pieChart recordIndex:(NSUInteger)index
{
    CGColorRef plotFillColor  = [CPTPieChart defaultPieSliceColorForIndex:index].cgColor;
    CGColorRef inputFillColor = (CGColorRef)[self areaFillColor:0];

    const CGFloat *plotColorComponents  = CGColorGetComponents(plotFillColor);
    const CGFloat *inputColorComponents = CGColorGetComponents(inputFillColor);

    CGColorRef fillColor = CGColorCreateGenericRGB(plotColorComponents[0] * inputColorComponents[0],
                                                   plotColorComponents[1] * inputColorComponents[1],
                                                   plotColorComponents[2] * inputColorComponents[2],
                                                   plotColorComponents[3] * inputColorComponents[3]);

    CPTColor *fillCPColor = [CPTColor colorWithCGColor:fillColor];

    CGColorRelease(fillColor);

    return [[CPTFill alloc] initWithColor:fillCPColor];
}

-(nullable CPTTextLayer *)sliceLabelForPieChart:(nonnull CPTPieChart *)pieChart recordIndex:(NSUInteger)index
{
    NSUInteger plotIndex = [[self.graph allPlots] indexOfObject:pieChart];
    NSString *key        = [NSString stringWithFormat:@"plotLabels%lu", (unsigned long)plotIndex];

    CPTDictionary *dict = [self valueForInputKey:key];

    if ( !dict ) {
        return nil;
    }

    NSString *label = dict[[NSString stringWithFormat:@"%lu", (unsigned long)index]];

    CPTTextLayer *layer = [[CPTTextLayer alloc] initWithText:label];
    [layer sizeToFit];

    CPTMutableTextStyle *style = [CPTMutableTextStyle textStyle];
    style.color     = [CPTColor colorWithCGColor:self.inputLabelColor];
    layer.textStyle = style;

    return layer;
}

@end
