"use strict";
/**
 * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author Michal Malý <michal.maly@ibt.cas.cz>
 * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfalPyramidsRepresentationProvider = exports.ConfalPyramidsRepresentation = exports.getConfalPyramidsParams = exports.ConfalPyramidsParams = void 0;
var tslib_1 = require("tslib");
var property_1 = require("./property");
var util_1 = require("./util");
var types_1 = require("./types");
var mesh_1 = require("../../../mol-geo/geometry/mesh/mesh");
var mesh_builder_1 = require("../../../mol-geo/geometry/mesh/mesh-builder");
var primitive_1 = require("../../../mol-geo/primitive/primitive");
var location_iterator_1 = require("../../../mol-geo/util/location-iterator");
var linear_algebra_1 = require("../../../mol-math/linear-algebra");
var loci_1 = require("../../../mol-model/loci");
var structure_1 = require("../../../mol-model/structure");
var representation_1 = require("../../../mol-repr/representation");
var representation_2 = require("../../../mol-repr/structure/representation");
var units_visual_1 = require("../../../mol-repr/structure/units-visual");
var common_1 = require("../../../mol-repr/structure/visual/util/common");
var param_definition_1 = require("../../../mol-util/param-definition");
var location_1 = require("../../../mol-model/location");
var t = linear_algebra_1.Mat4.identity();
var w = linear_algebra_1.Vec3.zero();
var mp = linear_algebra_1.Vec3.zero();
function calcMidpoint(mp, v, w) {
    linear_algebra_1.Vec3.sub(mp, v, w);
    linear_algebra_1.Vec3.scale(mp, mp, 0.5);
    linear_algebra_1.Vec3.add(mp, mp, w);
}
function shiftVertex(vec, ref, scale) {
    linear_algebra_1.Vec3.sub(w, vec, ref);
    linear_algebra_1.Vec3.scale(w, w, scale);
    linear_algebra_1.Vec3.add(vec, vec, w);
}
var ConfalPyramidsMeshParams = (0, tslib_1.__assign)({}, units_visual_1.UnitsMeshParams);
function createConfalPyramidsIterator(structureGroup) {
    var structure = structureGroup.structure, group = structureGroup.group;
    var instanceCount = group.units.length;
    var prop = property_1.ConfalPyramidsProvider.get(structure.model).value;
    if (prop === undefined || prop.data === undefined) {
        return (0, location_iterator_1.LocationIterator)(0, 1, 1, function () { return location_1.NullLocation; });
    }
    var locations = prop.data.locations;
    var getLocation = function (groupIndex, instanceIndex) {
        if (locations.length <= groupIndex)
            return location_1.NullLocation;
        return locations[groupIndex];
    };
    return (0, location_iterator_1.LocationIterator)(locations.length, instanceCount, 1, getLocation);
}
function createConfalPyramidsMesh(ctx, unit, structure, theme, props, mesh) {
    if (!structure_1.Unit.isAtomic(unit))
        return mesh_1.Mesh.createEmpty(mesh);
    var prop = property_1.ConfalPyramidsProvider.get(structure.model).value;
    if (prop === undefined || prop.data === undefined)
        return mesh_1.Mesh.createEmpty(mesh);
    var pyramids = prop.data.pyramids;
    if (pyramids.length === 0)
        return mesh_1.Mesh.createEmpty(mesh);
    var mb = mesh_builder_1.MeshBuilder.createState(512, 512, mesh);
    var handler = function (pyramid, first, second, firsLocIndex, secondLocIndex) {
        if (firsLocIndex === -1 || secondLocIndex === -1)
            throw new Error('Invalid location index');
        var scale = (pyramid.confal_score - 20.0) / 100.0;
        var O3 = first.O3.pos;
        var OP1 = second.OP1.pos;
        var OP2 = second.OP2.pos;
        var O5 = second.O5.pos;
        var P = second.P.pos;
        shiftVertex(O3, P, scale);
        shiftVertex(OP1, P, scale);
        shiftVertex(OP2, P, scale);
        shiftVertex(O5, P, scale);
        calcMidpoint(mp, O3, O5);
        mb.currentGroup = firsLocIndex;
        var pb = (0, primitive_1.PrimitiveBuilder)(3);
        /* Upper part (for first residue in step) */
        pb.add(O3, OP1, OP2);
        pb.add(O3, mp, OP1);
        pb.add(O3, OP2, mp);
        mesh_builder_1.MeshBuilder.addPrimitive(mb, t, pb.getPrimitive());
        /* Lower part (for second residue in step */
        mb.currentGroup = secondLocIndex;
        pb = (0, primitive_1.PrimitiveBuilder)(3);
        pb.add(mp, O5, OP1);
        pb.add(mp, OP2, O5);
        pb.add(O5, OP2, OP1);
        mesh_builder_1.MeshBuilder.addPrimitive(mb, t, pb.getPrimitive());
    };
    var walker = new util_1.ConfalPyramidsUtil.UnitWalker(structure, unit, handler);
    walker.walk();
    return mesh_builder_1.MeshBuilder.getMesh(mb);
}
function getConfalPyramidLoci(pickingId, structureGroup, id) {
    var groupId = pickingId.groupId, objectId = pickingId.objectId, instanceId = pickingId.instanceId;
    if (objectId !== id)
        return loci_1.EmptyLoci;
    var structure = structureGroup.structure;
    var unit = structureGroup.group.units[instanceId];
    if (!structure_1.Unit.isAtomic(unit))
        return loci_1.EmptyLoci;
    var prop = property_1.ConfalPyramidsProvider.get(structure.model).value;
    if (prop === undefined || prop.data === undefined)
        return loci_1.EmptyLoci;
    var locations = prop.data.locations;
    if (locations.length <= groupId)
        return loci_1.EmptyLoci;
    var altId = structure_1.StructureProperties.atom.label_alt_id(types_1.ConfalPyramidsTypes.toElementLocation(locations[groupId]));
    var rI = unit.residueIndex[locations[groupId].element.element];
    return (0, common_1.getAltResidueLociFromId)(structure, unit, rI, altId);
}
function eachConfalPyramid(loci, structureGroup, apply) {
    return false; // TODO: Implement me
}
function ConfalPyramidsVisual(materialId) {
    return (0, units_visual_1.UnitsMeshVisual)({
        defaultProps: param_definition_1.ParamDefinition.getDefaultValues(ConfalPyramidsMeshParams),
        createGeometry: createConfalPyramidsMesh,
        createLocationIterator: createConfalPyramidsIterator,
        getLoci: getConfalPyramidLoci,
        eachLocation: eachConfalPyramid,
        setUpdateState: function (state, newProps, currentProps) {
        }
    }, materialId);
}
var ConfalPyramidsVisuals = {
    'confal-pyramids-symbol': function (ctx, getParams) { return (0, representation_2.UnitsRepresentation)('Confal Pyramids Symbol Mesh', ctx, getParams, ConfalPyramidsVisual); },
};
exports.ConfalPyramidsParams = (0, tslib_1.__assign)({}, units_visual_1.UnitsMeshParams);
function getConfalPyramidsParams(ctx, structure) {
    return param_definition_1.ParamDefinition.clone(exports.ConfalPyramidsParams);
}
exports.getConfalPyramidsParams = getConfalPyramidsParams;
function ConfalPyramidsRepresentation(ctx, getParams) {
    var repr = representation_1.Representation.createMulti('Confal Pyramids', ctx, getParams, representation_2.StructureRepresentationStateBuilder, ConfalPyramidsVisuals);
    return repr;
}
exports.ConfalPyramidsRepresentation = ConfalPyramidsRepresentation;
exports.ConfalPyramidsRepresentationProvider = (0, representation_2.StructureRepresentationProvider)({
    name: 'confal-pyramids',
    label: 'Confal Pyramids',
    description: 'Displays schematic depiction of conformer classes and confal values',
    factory: ConfalPyramidsRepresentation,
    getParams: getConfalPyramidsParams,
    defaultValues: param_definition_1.ParamDefinition.getDefaultValues(exports.ConfalPyramidsParams),
    defaultColorTheme: { name: 'confal-pyramids' },
    defaultSizeTheme: { name: 'uniform' },
    isApplicable: function (structure) { return structure.models.some(function (m) { return property_1.ConfalPyramids.isApplicable(m); }); },
    ensureCustomProperties: {
        attach: function (ctx, structure) { return property_1.ConfalPyramidsProvider.attach(ctx, structure.model, void 0, true); },
        detach: function (data) { return property_1.ConfalPyramidsProvider.ref(data.model, false); },
    }
});
//# sourceMappingURL=representation.js.map