+ -- choose source_stk or source_neg variable depending on flip state
+ if source.flip then
+ var = "neg"
+ else
+ var = "stk"
+ end
+
+ -- create legend
+ legend = _sf( "%-" .. _longest_name .. "s", source.title )
+
+ -- create area if not disabled
+ if not source.noarea then
+ _tif( _args, "AREA:%s_%s#%s", source.sname, var, area_color )
+ end
+
+ -- create line1 statement
+ _tif( _args, "LINE1:%s_%s#%s:%s", source.sname, var, line_color, legend )
+ end
+
+ -- local helper: create gprint statements
+ function __gprint(source)
+
+ local numfmt = opts.number_format or "%6.1lf"
+ local totfmt = opts.totals_format or "%5.1lf%s"
+
+ -- don't include MIN if rrasingle is enabled
+ if not self.opts.rrasingle then
+ _tif( _args, "GPRINT:%s_min:MIN:%s Min", source.sname, numfmt )
+ end
+
+ -- always include AVERAGE
+ _tif( _args, "GPRINT:%s_avg:AVERAGE:%s Avg", source.sname, numfmt )
+
+ -- don't include MAX if rrasingle is enabled
+ if not self.opts.rrasingle then
+ _tif( _args, "GPRINT:%s_max:MAX:%s Max", source.sname, numfmt )
+ end
+
+ -- include total count if requested else include LAST
+ if source.total then
+ _tif( _args, "GPRINT:%s_avg_sum:LAST:(ca. %s Total)\\l", source.sname, totfmt )
+ else
+ _tif( _args, "GPRINT:%s_avg:LAST:%s Last\\l", source.sname, numfmt )
+ end
+ end
+
+
+ --
+ -- find all data sources
+ --
+
+ -- find data types
+ local data_types
+
+ if dtype then
+ data_types = { dtype }
+ else
+ data_types = opts.data.types or { }
+ end
+
+ if not ( dtype or opts.data.types ) then
+ if opts.data.instances then
+ for k, v in pairs(opts.data.instances) do
+ _ti( data_types, k )
+ end
+ elseif opts.data.sources then
+ for k, v in pairs(opts.data.sources) do
+ _ti( data_types, k )
+ end
+ end
+ end
+
+
+ -- iterate over data types
+ for i, dtype in ipairs(data_types) do
+
+ -- find instances
+
+ local data_instances
+
+ if not opts.per_instance then
+ if type(opts.data.instances) == "table" and type(opts.data.instances[dtype]) == "table" then
+ data_instances = opts.data.instances[dtype]
+ else
+ data_instances = self.tree:data_instances( plugin, plugin_instance, dtype )
+ end
+ end
+
+ if type(data_instances) ~= "table" or #data_instances == 0 then data_instances = { "" } end
+
+
+ -- iterate over data instances
+ for i, dinst in ipairs(data_instances) do
+
+ -- construct combined data type / instance name
+ local dname = dtype
+
+ if dinst:len() > 0 then
+ dname = dname .. "_" .. dinst
+ end
+
+
+ -- find sources
+ local data_sources = { "value" }
+
+ if type(opts.data.sources) == "table" then
+ if type(opts.data.sources[dname]) == "table" then
+ data_sources = opts.data.sources[dname]
+ elseif type(opts.data.sources[dtype]) == "table" then
+ data_sources = opts.data.sources[dtype]
+ end
+ end
+
+
+ -- iterate over data sources
+ for i, dsource in ipairs(data_sources) do
+
+ local dsname = dtype .. "_" .. dinst:gsub("[^%w]","_") .. "_" .. dsource
+ local altname = dtype .. "__" .. dsource
+
+ -- find datasource options
+ local dopts = { }
+
+ if type(opts.data.options) == "table" then
+ if type(opts.data.options[dsname]) == "table" then
+ dopts = opts.data.options[dsname]
+ elseif type(opts.data.options[altname]) == "table" then
+ dopts = opts.data.options[altname]
+ elseif type(opts.data.options[dname]) == "table" then
+ dopts = opts.data.options[dname]
+ elseif type(opts.data.options[dtype]) == "table" then
+ dopts = opts.data.options[dtype]
+ end
+ end
+
+
+ -- store values
+ _ti( _sources, {
+ rrd = dopts.rrd or self:mkrrdpath( plugin, plugin_instance, dtype, dinst ),
+ color = dopts.color or self.colors:to_string( self.colors:random() ),
+ flip = dopts.flip or false,
+ total = dopts.total or false,
+ overlay = dopts.overlay or false,
+ noarea = dopts.noarea or false,
+ ds = dsource,
+ type = dtype,
+ instance = dinst,
+ index = #_sources + 1,
+ sname = ( #_sources + 1 ) .. dtype
+ } )
+
+
+ -- generate datasource title
+ _sources[#_sources].title = self.i18n:ds( _sources[#_sources] )
+
+
+ -- find longest name ...
+ if _sources[#_sources].title:len() > _longest_name then
+ _longest_name = _sources[#_sources].title:len()
+ end
+
+
+ -- has totals?
+ if _sources[#_sources].total then
+ _has_totals = true
+ end
+ end
+ end
+ end
+
+
+ --
+ -- construct diagrams
+ --
+
+ -- if per_instance is enabled then find all instances from the first datasource in diagram
+ -- if per_instance is disabled then use an empty pseudo instance and use model provided values
+ local instances = { "" }
+
+ if opts.per_instance then
+ instances = self.tree:data_instances( plugin, plugin_instance, _sources[1].type )
+ end
+
+
+ -- iterate over instances
+ for i, instance in ipairs(instances) do
+
+ -- store title and vlabel
+ _ti( _args, "-t" )
+ _ti( _args, opts.title or self.i18n:title( plugin, plugin_instance, _sources[1].type, instance ) )
+ _ti( _args, "-v" )
+ _ti( _args, opts.vlabel or self.i18n:label( plugin, plugin_instance, _sources[1].type, instance ) )
+
+ -- store additional rrd options
+ if opts.rrdopts then
+ for i, o in ipairs(opts.rrdopts) do _ti( _args, o ) end
+ end
+
+
+ -- create DEF statements for each instance
+ for i, source in ipairs(_sources) do
+ -- fixup properties for per instance mode...
+ if opts.per_instance then
+ source.instance = instance
+ source.rrd = self:mkrrdpath( plugin, plugin_instance, source.type, instance )
+ end
+
+ __def( source )
+ end