<commit_before>﻿/// <reference path="../bpmn-js.d.ts" />
import * as Modeler from "bpmn-js/lib/Modeler"
import * as BpmnRenderer from "bpmn-js/lib/draw/BpmnRenderer"
import * as moment from 'moment'
import { WorkflowConditionEntity, WorkflowActionEntity, DecisionResult, CaseActivityEntity, CaseNotificationEntity, DoneType, WorkflowActivityEntity, CaseFlowColor } from '../Signum.Entities.Workflow'
import { Lite, liteKey } from '../../../../Framework/Signum.React/Scripts/Signum.Entities'
import { CustomRenderer } from './CustomRenderer'
import { Color, Gradient } from '../../Basics/Color'
import { CaseFlow, CaseConnectionStats, CaseActivityStats  } from '../WorkflowClient'
import * as BpmnUtils from './BpmnUtils'
import { calculatePoint, Rectangle } from "../../Map/Utils"
import * as NavigatedViewer from "bpmn-js/lib/NavigatedViewer"
import "moment-duration-format"

export class CaseFlowRenderer extends CustomRenderer {

    constructor(eventBus: BPMN.EventBus, styles: any, pathMap: any, canvas: any, priority: number) {
        super(eventBus, styles, pathMap, canvas, 1200);
    }

    caseFlow: CaseFlow;

    viewer: NavigatedViewer;

    drawConnection(visuals: any, element: BPMN.DiElement) {

        const path = super.drawConnection(visuals, element);

        const stats = this.caseFlow.Connections[element.id];

        if (!stats)
            path.style.setProperty('stroke', "lightgray");
        else {
            const pathGroup = (path.parentNode as SVGGElement).parentNode as SVGGElement;
            const title = (Array.toArray(pathGroup.childNodes) as SVGElement[]).filter(a => a.nodeName == "title").firstOrNull() || pathGroup.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "title"));
            title.textContent = stats.map(con => `${DoneType.niceName(con.DoneType)} (${con.DoneBy.toStr} ${moment(con.DoneDate).fromNow()})`).join("\n");
        }

        return path;
    }    

    caseFlowColor?: CaseFlowColor;
    maxDuration: number;

    gradient = new Gradient([
        { value: 0, color: Color.parse("rgb(117, 202, 112)")},
        { value: 0.5, color: Color.parse("rgb(251, 214, 95)") },
        { value: 1, color: Color.parse("rgb(251, 114, 95)") },
    ]);
    
    drawShape(visuals: any, element: BPMN.DiElement) {
        
        const result = super.drawShape(visuals, element);

        if (BpmnUtils.isLabel(element.type)) {
            if (!this.caseFlow.AllNodes.contains(element.businessObject.id) &&
                !this.caseFlow.Connections[element.businessObject.id])
                result.style.setProperty('fill', "gray");
        }
        else if (BpmnUtils.isStartEvent(element.type) ||
            BpmnUtils.isEndEvent(element.type) ||
            BpmnUtils.isGatewayAnyKind(element.type)) {

            if (!this.caseFlow.AllNodes.contains(element.id)) {
                result.style.setProperty('stroke', "lightgray");
                result.style.setProperty('fill', "#eee");

                //debugger;
            }
        }
        else if (BpmnUtils.isTaskAnyKind(element.type)) {

            const stats = this.caseFlow.Activities[element.id];
            if (!stats) {
                result.style.setProperty('stroke', "lightgray");
                result.style.setProperty('fill', "#eee");
            } else {
                const compare =
                    this.caseFlowColor == "AverageDuration" ? (stats[0].AverageDuration == undefined ? undefined : stats[0].AverageDuration! * 2) :
                        this.caseFlowColor == "EstimatedDuration" ? (stats[0].EstimatedDuration == undefined ? undefined : stats[0].EstimatedDuration! * 2) :
                            this.caseFlowColor == "CaseMaxDuration" ? this.maxDuration : undefined;

                const sumDuration = stats.map(a => a.Duration || 0).sum();          

                if (compare != null && sumDuration > 0) {
                    const color = this.gradient.getColor(sumDuration / compare);

                    result.style.setProperty('stroke', color.lerp(0.5, Color.Black).toString());
                    result.style.setProperty('fill', color.toString());
                }

                const gParent = ((result.parentNode as SVGGElement).parentNode as SVGGElement);
                const title = (Array.toArray(gParent.childNodes) as SVGElement[]).filter(a => a.nodeName == "title").firstOrNull() || gParent.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "title"));
                title.textContent = stats.map((a, i) => i == 0 || i == stats.length - 1 ? getTitle(a) :
                    i == 1 ? `(…${CaseActivityEntity.niceCount(stats.length - 2)})` : "").filter(a => a).join("\n\n");

                const ggParent = gParent.parentNode as SVGGElement;

                const pathGroups = (Array.toArray(ggParent.childNodes) as SVGPathElement[]).filter(a => a.nodeName == "g" && a.className== "jump-group");
                const jumps = this.caseFlow.Jumps.filter(j => j.FromBpmnElementId == element.id);
                
                const toCenteredRectangle = (bounds: BPMN.BoundsElement) => ({
                    x: bounds.x + bounds.width / 2,
                    y: bounds.y + bounds.height / 2,
                    width: bounds.width,
                    height: bounds.height
                }) as Rectangle;

                pathGroups.slice(jumps.length).forEach(path => (path.parentNode as SVGGElement).removeChild(path));

                if (jumps.length) {
                    const moddleElements = ((this.viewer as any).definitions.diagrams[0].plane.planeElement as BPMN.ModdleElement[]);<commit_msg>fix for updating to new version of bpmn.io package<commit_after>﻿/// <reference path="../bpmn-js.d.ts" />
import * as Modeler from "bpmn-js/lib/Modeler"
import * as BpmnRenderer from "bpmn-js/lib/draw/BpmnRenderer"
import * as moment from 'moment'
import { WorkflowConditionEntity, WorkflowActionEntity, DecisionResult, CaseActivityEntity, CaseNotificationEntity, DoneType, WorkflowActivityEntity, CaseFlowColor } from '../Signum.Entities.Workflow'
import { Lite, liteKey } from '../../../../Framework/Signum.React/Scripts/Signum.Entities'
import { CustomRenderer } from './CustomRenderer'
import { Color, Gradient } from '../../Basics/Color'
import { CaseFlow, CaseConnectionStats, CaseActivityStats  } from '../WorkflowClient'
import * as BpmnUtils from './BpmnUtils'
import { calculatePoint, Rectangle } from "../../Map/Utils"
import * as NavigatedViewer from "bpmn-js/lib/NavigatedViewer"
import "moment-duration-format"

export class CaseFlowRenderer extends CustomRenderer {

    constructor(eventBus: BPMN.EventBus, styles: any, pathMap: any, canvas: any, priority: number) {
        super(eventBus, styles, pathMap, canvas, 1200);
    }

    caseFlow: CaseFlow;

    viewer: NavigatedViewer;

    drawConnection(visuals: any, element: BPMN.DiElement) {

        const path = super.drawConnection(visuals, element);

        const stats = this.caseFlow.Connections[element.id];

        if (!stats)
            path.style.setProperty('stroke', "lightgray");
        else {
            const pathGroup = (path.parentNode as SVGGElement).parentNode as SVGGElement;
            const title = (Array.toArray(pathGroup.childNodes) as SVGElement[]).filter(a => a.nodeName == "title").firstOrNull() || pathGroup.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "title"));
            title.textContent = stats.map(con => `${DoneType.niceName(con.DoneType)} (${con.DoneBy.toStr} ${moment(con.DoneDate).fromNow()})`).join("\n");
        }

        return path;
    }    

    caseFlowColor?: CaseFlowColor;
    maxDuration: number;

    gradient = new Gradient([
        { value: 0, color: Color.parse("rgb(117, 202, 112)")},
        { value: 0.5, color: Color.parse("rgb(251, 214, 95)") },
        { value: 1, color: Color.parse("rgb(251, 114, 95)") },
    ]);
    
    drawShape(visuals: any, element: BPMN.DiElement) {
        
        const result = super.drawShape(visuals, element);

        if (BpmnUtils.isLabel(element.type)) {
            if (!this.caseFlow.AllNodes.contains(element.businessObject.id) &&
                !this.caseFlow.Connections[element.businessObject.id])
                result.style.setProperty('fill', "gray");
        }
        else if (BpmnUtils.isStartEvent(element.type) ||
            BpmnUtils.isEndEvent(element.type) ||
            BpmnUtils.isGatewayAnyKind(element.type)) {

            if (!this.caseFlow.AllNodes.contains(element.id)) {
                result.style.setProperty('stroke', "lightgray");
                result.style.setProperty('fill', "#eee");

                //debugger;
            }
        }
        else if (BpmnUtils.isTaskAnyKind(element.type)) {

            const stats = this.caseFlow.Activities[element.id];
            if (!stats) {
                result.style.setProperty('stroke', "lightgray");
                result.style.setProperty('fill', "#eee");
            } else {
                const compare =
                    this.caseFlowColor == "AverageDuration" ? (stats[0].AverageDuration == undefined ? undefined : stats[0].AverageDuration! * 2) :
                        this.caseFlowColor == "EstimatedDuration" ? (stats[0].EstimatedDuration == undefined ? undefined : stats[0].EstimatedDuration! * 2) :
                            this.caseFlowColor == "CaseMaxDuration" ? this.maxDuration : undefined;

                const sumDuration = stats.map(a => a.Duration || 0).sum();          

                if (compare != null && sumDuration > 0) {
                    const color = this.gradient.getColor(sumDuration / compare);

                    result.style.setProperty('stroke', color.lerp(0.5, Color.Black).toString());
                    result.style.setProperty('fill', color.toString());
                }

                const gParent = ((result.parentNode as SVGGElement).parentNode as SVGGElement);
                const title = (Array.toArray(gParent.childNodes) as SVGElement[]).filter(a => a.nodeName == "title").firstOrNull() || gParent.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "title"));
                title.textContent = stats.map((a, i) => i == 0 || i == stats.length - 1 ? getTitle(a) :
                    i == 1 ? `(…${CaseActivityEntity.niceCount(stats.length - 2)})` : "").filter(a => a).join("\n\n");

                const ggParent = gParent.parentNode as SVGGElement;

                const pathGroups = (Array.toArray(ggParent.childNodes) as SVGPathElement[]).filter(a => a.nodeName == "g" && a.className== "jump-group");
                const jumps = this.caseFlow.Jumps.filter(j => j.FromBpmnElementId == element.id);
                
                const toCenteredRectangle = (bounds: BPMN.BoundsElement) => ({
                    x: bounds.x + bounds.width / 2,
                    y: bounds.y + bounds.height / 2,
                    width: bounds.width,
                    height: bounds.height
                }) as Rectangle;

                pathGroups.slice(jumps.length).forEach(path => (path.parentNode as SVGGElement).removeChild(path));

                if (jumps.length) {
                    const moddleElements = ((this.viewer as any)._definitions.diagrams[0].plane.planeElement as BPMN.ModdleElement[]);
{'fraction_non_alphanumeric': 0.14193719124911786, 'fraction_numerical': 0.01058574453069866, 'mean_word_length': 2.4627367135003055, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4438358', 'n_tokens_mistral': 3392, 'n_tokens_neox': 3191, 'n_words': 635}