@Override
public List<AjtColumnInfo<Demand>> getNonBasicUserDefinedColumnsVisibleOrNot()
{
final List<AjtColumnInfo<Demand>> res = new LinkedList<> ();
res.add(new AjtColumnInfo<Demand>(this , Node.class, null , "A", "Ingress node", null , d->d.getIngressNode() , AGTYPE.NOAGGREGATION , null));
res.add(new AjtColumnInfo<Demand>(this , Node.class, null , "B", "Egress node", null , d->d.getEgressNode() , AGTYPE.NOAGGREGATION , null));
res.add(new AjtColumnInfo<Demand>(this , Demand.class, null , "Bidirectional pair", "If the demand is bidirectional, provides its bidirectional pair", null , d->d.getBidirectionalPair() , AGTYPE.NOAGGREGATION, null));
res.add(new AjtColumnInfo<Demand>(this , Link.class, null , "Link coupled", "The link that this demand is coupled to (in this or other layer)", null , d->d.getCoupledLink() , AGTYPE.NOAGGREGATION , null));
res.add(new AjtColumnInfo<Demand>(this , Double.class, null , "Offered traffic (" + getTableNetworkLayer().getLinkCapacityUnits() + ")", "Offered traffic by the demand", (d,val)->d.setOfferedTraffic((Double) val), d->d.getOfferedTraffic() , AGTYPE.SUMDOUBLE , null));
res.add(new AjtColumnInfo<Demand>(this , Double.class, null , "Carried traffic (" + getTableNetworkLayer().getLinkCapacityUnits() + ")", "Carried traffic by the demand", null , d->d.getCarriedTraffic() , AGTYPE.SUMDOUBLE , null));
res.add(new AjtColumnInfo<Demand>(this , Double.class, null , "% Lost traffic", "Percentage of the lost traffic by the demand", null, d->d.getOfferedTraffic() == 0? 0 : d.getBlockedTraffic() / d.getOfferedTraffic() , AGTYPE.NOAGGREGATION , d->d.getBlockedTraffic() > 0? Color.RED : Color.GREEN));
res.add(new AjtColumnInfo<Demand>(this , String.class, null , "QoS type", "A used-defined string identifying the type of traffic of the demand", (d,val)-> d.setQoSType((String)val) , d->d.getQosType(), AGTYPE.NOAGGREGATION , null));
res.add(new AjtColumnInfo<Demand>(this , Boolean.class, null , "Source routing?", "", (d,val)->d.setRoutingType((Boolean) val? RoutingType.SOURCE_ROUTING : RoutingType.HOP_BY_HOP_ROUTING), d->d.isSourceRouting() , AGTYPE.COUNTTRUE , null));
res.add(new AjtColumnInfo<Demand>(this , Boolean.class, null , "Is service chain?", "", null, d->d.isServiceChainRequest() , AGTYPE.COUNTTRUE , null));
res.add(new AjtColumnInfo<Demand>(this , String.class, null , "Resource types", "The sequence of resource types that has to be traversed by the routes of the demand, if it is a service chain", null, d->d.isSourceRouting()? d.getServiceChainSequenceOfTraversedResourceTypes().stream().collect(Collectors.joining(",")) : "" , AGTYPE.COUNTTRUE , null));
res.add(new AjtColumnInfo<Demand>(this , String.class, null , "Routing cycles", "Indicates whether there are routing cycles: loopless (no cycle in some route), open cycles (traffic reaches egress node after some cycles in some route), closed cycles (traffic does not reach the egress node in some route)", null, d->d.getRoutingCycleType().name() , AGTYPE.NOAGGREGATION , d->d.getRoutingCycleType() == RoutingCycleType.LOOPLESS? null : Color.ORANGE));
res.add(new AjtColumnInfo<Demand>(this , String.class, null , "Bifurcated?", "Indicates whether the demand is satisfied by more than one path from origin to destination", null, d->!d.isSourceRouting() ? "-" : (d.isBifurcated()) ? String.format("Yes (%d)", d.getRoutes().size()) : "No" , AGTYPE.NOAGGREGATION , null));
res.add(new AjtColumnInfo<Demand>(this , Integer.class, null , "# routes", "Number of associated routes", null, d->!d.isSourceRouting() ? 0 : d.getRoutes().size() , AGTYPE.SUMINT, null));
res.add(new AjtColumnInfo<Demand>(this , Double.class, null , "Worst e2e lat (ms)", "Current worst case end-to-end propagation time in miliseconds (accumulating any lower layer propagation times if any)", null, d->d.getWorstCasePropagationTimeInMs() , AGTYPE.NOAGGREGATION , d->{ final double maxMs = d.getMaximumAcceptableE2EWorstCaseLatencyInMs(); return maxMs <= 0? null : (d.getWorstCasePropagationTimeInMs() > maxMs? Color.RED : null); }));
res.add(new AjtColumnInfo<Demand>(this , Double.class, null , "Worst e2e length (km)", "Current worst case end-to-end propagation length in km (accumulating any lower layer propagation lengths if any)", null, d->d.getWorstCaseLengthInKm() , AGTYPE.NOAGGREGATION , null));
res.add(new AjtColumnInfo<Demand>(this , Double.class, null , "Limit e2e lat (ms)", "Maximum end-to-end propagation time in miliseconds (accumulating any lower layer propagation times if any)", (d,val)-> d.setMaximumAcceptableE2EWorstCaseLatencyInMs((Double)val) , d->d.getMaximumAcceptableE2EWorstCaseLatencyInMs() , AGTYPE.NOAGGREGATION , null));
res.add(new AjtColumnInfo<Demand>(this , Double.class, null , "CAGR(%)" , "Compound annual growth factor for this demand", (d,val)->d.setOfferedTrafficPerPeriodGrowthFactor((Double) val), d->d.getOfferedTrafficPerPeriodGrowthFactor() , AGTYPE.NOAGGREGATION , null));
res.add(new AjtColumnInfo<Demand>(this , Integer.class, null , "#Monit points" , "Number of samples of the offered traffic stored, coming from a monitoring or forecasting traffic process", null , d->d.getMonitoredOrForecastedOfferedTraffic().getSize() , AGTYPE.NOAGGREGATION , null));
return res;
}