<%
  const type = locals.type;
  const layoutProperties = locals.layoutProperties;
  const paintProperties = locals.paintProperties;
  const enumProperties = locals.enumProperties;
-%>
// This file is generated. 
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.

#import "MGLSource.h"
#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGL<%- camelize(type) %>StyleLayer.h"

#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
<% if (enumProperties) { -%>

namespace mbgl {

<% if (layoutProperties.length) { -%>
<% for (const property of layoutProperties) { -%>
<% if (property.type == "enum") { -%>
    MBGL_DEFINE_ENUM(MGL<%- camelize(property.name) %>, {
<% for (const value in property.values) { -%>
        { MGL<%- camelize(property.name) %><%- camelize(value) %>, "<%-value%>" },
<% } -%>
    });

<% } -%>
<% } -%>
<% } -%>
<% if (paintProperties.length) { -%>
<% for (const property of paintProperties) { -%>
<% if (property.type == "enum") { -%>
    MBGL_DEFINE_ENUM(MGL<%- camelize(property.name) %>, {
<% for (const value in property.values) { -%>
        { MGL<%- camelize(property.name) %><%- camelize(value) %>, "<%-value%>" },
<% } -%>
    });

<% } -%>
<% } -%>
<% } -%>
}
<% } -%>

@interface MGL<%- camelize(type) %>StyleLayer ()

@property (nonatomic) mbgl::style::<%- camelize(type) %>Layer *rawLayer;

@end

@implementation MGL<%- camelize(type) %>StyleLayer
{
    std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer> _pendingLayer;
}

<% if (type == 'background') { -%>
- (instancetype)initWithIdentifier:(NSString *)identifier
{
    if (self = [super initWithIdentifier:identifier]) {
        auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String);
        _pendingLayer = std::move(layer);
        self.rawLayer = _pendingLayer.get();
    }
    return self;
}

<% } else { -%>
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
{
    if (self = [super initWithIdentifier:identifier source:source]) {
        auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String, source.identifier.UTF8String);
        _pendingLayer = std::move(layer);
        self.rawLayer = _pendingLayer.get();
    }
    return self;
}

<% } -%>
- (mbgl::style::<%- camelize(type) %>Layer *)rawLayer
{
    return (mbgl::style::<%- camelize(type) %>Layer *)super.rawLayer;
}

- (void)setRawLayer:(mbgl::style::<%- camelize(type) %>Layer *)rawLayer
{
    super.rawLayer = rawLayer;
}

<% if (type !== 'background') { -%>
- (NSString *)sourceIdentifier
{
    MGLAssertStyleLayerIsValid();
    
    return @(self.rawLayer->getSourceID().c_str());
}

<% if (type !== 'raster') { -%>
- (NSString *)sourceLayerIdentifier
{
    MGLAssertStyleLayerIsValid();

    auto layerID = self.rawLayer->getSourceLayer();
    return layerID.empty() ? nil : @(layerID.c_str());
}

- (void)setSourceLayerIdentifier:(NSString *)sourceLayerIdentifier
{
    MGLAssertStyleLayerIsValid();

    self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
}

- (void)setPredicate:(NSPredicate *)predicate
{
    MGLAssertStyleLayerIsValid();

    self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
}

- (NSPredicate *)predicate
{
    MGLAssertStyleLayerIsValid();

    return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}

<% }} -%>
#pragma mark - Adding to and removing from a map view

- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
{
    if (_pendingLayer == nullptr) {
        [NSException raise:@"MGLRedundantLayerException"
            format:@"This instance %@ was already added to %@. Adding the same layer instance " \
                    "to the style more than once is invalid.", self, mapView.style];
    }

    if (otherLayer) {
        const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
        mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
    } else {
        mapView.mbglMap->addLayer(std::move(_pendingLayer));
    }
}

- (void)removeFromMapView:(MGLMapView *)mapView
{
    _pendingLayer = nullptr;
    self.rawLayer = nullptr;

    auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
    if (!removedLayer) {
        return;
    }

    mbgl::style::<%- camelize(type) %>Layer *layer = dynamic_cast<mbgl::style::<%- camelize(type) %>Layer *>(removedLayer.get());
    if (!layer) {
        return;
    }

    removedLayer.release();

    _pendingLayer = std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer>(layer);
    self.rawLayer = _pendingLayer.get();
}

<% if (layoutProperties.length) { -%>
#pragma mark - Accessing the Layout Attributes

<% for (const property of layoutProperties) { -%>
- (void)set<%- camelize(property.name) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> {
    MGLAssertStyleLayerIsValid();

<% if (property.type == "enum") { -%>
    auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
    self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } else { -%>
    auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
    self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } -%>
}

- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> {
    MGLAssertStyleLayerIsValid();

    auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
<% if (property.type == "enum") { -%>
    return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
    return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
}

<% if (property.original) { -%>
- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
}

- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
    return self.<%- objCGetter(property) %>;
}

<% } -%>
<% } -%>
<% } -%>
<% if (paintProperties.length) { -%>
#pragma mark - Accessing the Paint Attributes

<% for (const property of paintProperties) { -%>
- (void)set<%- camelize(property.name) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> {
    MGLAssertStyleLayerIsValid();

<% if (property.type == "enum") { -%>
    auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
    self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } else { -%>
    auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
    self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
<% } -%>
}

- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> {
    MGLAssertStyleLayerIsValid();

    auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
<% if (property.type == "enum") { -%>
    return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
    return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
}

<% if (property.original) { -%>
- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
}

- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
    return self.<%- objCGetter(property) %>;
}

<% } -%>
<% } -%>
<% } -%>

@end
<% if (enumProperties) { -%>

@implementation NSValue (MGL<%- camelize(type) %>StyleLayerAdditions)

<% for (let property of enumProperties) { -%>
+ (NSValue *)valueWithMGL<%- camelize(property.name) %>:(MGL<%- camelize(property.name) %>)<%- objCName(property) %> {
    return [NSValue value:&<%- objCName(property) %> withObjCType:@encode(MGL<%- camelize(property.name) %>)];
}

- (MGL<%- camelize(property.name) %>)MGL<%- camelize(property.name) %>Value {
    MGL<%- camelize(property.name) %> <%- objCName(property) %>;
    [self getValue:&<%- objCName(property) %>];
    return <%- objCName(property) %>;
}

<% } -%>
@end
<% } -%>
