
// import { UnaryOperation, UnaryOperationType } from './types'
import { Type } from '../Core/types';
import SparqlTask from '../Core/SparqlTask';
import attributeGetter from '../SparqlAttribute/getter';
// import { parseValue } from '../SparqlObject/common'
import { copy } from './common';
// import DefinitionPattern from '../Query/DefinitionPattern'
import { ARITHMETIC_SYMBOL, arithmetic_filter } from './arithmetic_filter'
import { AGGREGATE_KEYORD, aggregate_filter } from './aggregate_filter'
import sparqljs from 'sparqljs';
import DefinitionPattern  from './DefinitionPattern';
import values from './_values';
import look_alike from './_filter_regex';


export enum UnaryOperationType {
    // EXACT_MATCH = 'EXACT_MATCH',
    LOOK_ALIKE = 'LOOK_ALIKE',
    FILTER = 'FILTER',
    GREATER = 'GREATER',
    LOWER = 'LOWER',
    EQUAL = 'EQUAL',
    AVG = 'AVG',
    AVG_GREATER = 'AVG_GREATER',
    AVG_LOWER = 'AVG_LOWER',
    SUM = 'SUM',
    SUM_GREATER = 'SUM_GREATER',
    SUM_LOWER = 'SUM_LOWER',
    COUNT = 'COUNT',
    COUNT_GREATER = 'COUNT_GREATER',
    COUNT_LOWER = 'COUNT_LOWER',
    MIN = 'MIN',
    MIN_GREATER = 'MIN_GREATER',
    MIN_LOWER = 'MIN_LOWER',
    MAX = 'MAX',
    MAX_GREATER = 'MAX_GREATER',
    MAX_LOWER = 'MAX_LOWER',
}

export interface UnaryOperation {
    operation: UnaryOperationType;
    json_pointers: string | string[];
    arguments?: any
}

export function unaryFunction(unaryOperation: UnaryOperation, definition: DefinitionPattern, reference: string) {

    switch (unaryOperation.operation) {
        case UnaryOperationType.FILTER:
            if (Array.isArray(unaryOperation.json_pointers)) {
                return values(reference, definition, unaryOperation.json_pointers, unaryOperation.arguments);
            } else {
                return values(reference, definition, [unaryOperation.json_pointers], unaryOperation.arguments);
            }
        case UnaryOperationType.LOOK_ALIKE:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return look_alike(reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        // Arithmetic attribute level
        case UnaryOperationType.EQUAL:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return arithmetic_filter(ARITHMETIC_SYMBOL.EQUAL, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Attributes and arguments must be non array'
            }
        case UnaryOperationType.GREATER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return arithmetic_filter(ARITHMETIC_SYMBOL.GREATER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Attributes and arguments must be non array'
            }
        case UnaryOperationType.LOWER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return arithmetic_filter(ARITHMETIC_SYMBOL.LOWER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Attributes and arguments must be non array'
            }


        // Aggregate arithmetic
        case UnaryOperationType.AVG:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.AVG, ARITHMETIC_SYMBOL.EQUAL, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.AVG_GREATER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.AVG, ARITHMETIC_SYMBOL.GREATER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.AVG_LOWER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.AVG, ARITHMETIC_SYMBOL.LOWER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }

        case UnaryOperationType.COUNT:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.COUNT, ARITHMETIC_SYMBOL.EQUAL, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.COUNT_GREATER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.COUNT, ARITHMETIC_SYMBOL.GREATER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.COUNT_LOWER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.COUNT, ARITHMETIC_SYMBOL.LOWER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }

        case UnaryOperationType.SUM:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.SUM, ARITHMETIC_SYMBOL.EQUAL, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.SUM_GREATER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.SUM, ARITHMETIC_SYMBOL.GREATER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.SUM_LOWER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.SUM, ARITHMETIC_SYMBOL.LOWER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }

        case UnaryOperationType.MAX:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.MAX, ARITHMETIC_SYMBOL.EQUAL, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.MAX_GREATER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.MAX, ARITHMETIC_SYMBOL.GREATER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.MAX_LOWER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.MAX, ARITHMETIC_SYMBOL.LOWER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }

        case UnaryOperationType.MIN:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.MIN, ARITHMETIC_SYMBOL.EQUAL, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.MIN_GREATER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.MIN, ARITHMETIC_SYMBOL.GREATER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }
        case UnaryOperationType.MIN_LOWER:
            if (!Array.isArray(unaryOperation.arguments) && !Array.isArray(unaryOperation.json_pointers)) {
                return aggregate_filter(AGGREGATE_KEYORD.MIN, ARITHMETIC_SYMBOL.LOWER, reference, definition, unaryOperation.json_pointers, unaryOperation.arguments)
            } else {
                throw 'Look alike parameters and arguments must be non array'
            }

        default:
            throw 'Not a valid unary operation'
    }

}






export function operationUnroller(reference: string, unaryOperationArray: UnaryOperation[]) {
    let _body = new DefinitionPattern(reference);
    return unaryOperationArray.reduce((body, operation) => {
        return unaryFunction(operation, body, reference);
    }, _body)
}
export default unaryFunction