<file_sep>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace OCLogInterpreter
{
    class LogFile
    {
        public List<Entry> m_entryList = new List<Entry>();

        public List<string> m_listOfPriorities = new List<string>();

        public void populatePriorities()
        {
            m_listOfPriorities.Clear();

            m_listOfPriorities.Add("");

            foreach (Entry e in m_entryList)
            {
                if (!m_listOfPriorities.Contains(e.m_priority))
                {
                    m_listOfPriorities.Add(e.m_priority);
                }
            }
        }

        public List<Entry> findEntriesByTimeDate(string filterTimeDate)
        {
            List<Entry> retList = new List<Entry>();

            foreach (Entry e in m_entryList)
            {
                if (e.m_dateTime.Contains(filterTimeDate))
                {
                    retList.Add(e);
                }
            }

            return retList;
        }

        public List<Entry> findEntriesByPriority(string filterPriority)
        {
            List<Entry> retList = new List<Entry>();

            foreach (Entry e in m_entryList)
            {
                if (e.m_priority.Contains(filterPriority))
                {
                    retList.Add(e);
                }
            }

            return retList;
        }

        public List<Entry> filterEntries(string filterPriority, string filterDateTime)
        {
            List<Entry> retList = new List<Entry>();

            foreach (Entry e in m_entryList)
            {
                if (e.m_priority.Contains(filterPriority) && e.m_dateTime.Contains(filterDateTime) )
                {
                    retList.Add(e);
                }
            }

            return retList;
        }

        public void loadFromFile(string path)
        {
            m_entryList.Clear();
            m_listOfPriorities.Clear();

            StreamReader sr = new StreamReader(path);

            try
            {
                while (!sr.EndOfStream)
                {
                    m_entryList.Add(Entry.unSerialize(sr.ReadLine()));
                }
                populatePriorities();
            }
            finally
            {
                sr.Close();
            }
        }

        public void exportAsCSV(string path)
        {
            StreamWriter sw = new StreamWriter(path);

            try
            {
                sw.WriteLine("Date/Time,Log Information,Priority");
                foreach (Entry e in m_entryList)
                {
                    sw.WriteLine(e.toCSVFormat());
                }
            }
            finally
            {
                sw.Close();
            }
        }
    }

    class Entry
    {
        public string m_dateTime = "";
        public string m_info = "";
        public string m_priority = "";

        public override string ToString()
        {
            return m_dateTime + ": " + m_priority;
        }

        public static Entry unSerialize(string data)
        {

            Entry newEntry = new Entry();

            int part = 0;

            char[] charrdata = data.ToCharArray();

            foreach (char c in charrdata)
            {
                if (c == '|')
                {
                    part++;
                }
                else
                {
                    switch (part)
                    {
                        case 1:
                            newEntry.m_dateTime += c;
                            break;
                        case 2:
                            newEntry.m_info += c;
                            break;
                        case 3:
                            newEntry.m_priority += c;
                            break;
                    }
                }
            }

            return newEntry;
        }

        public string toCSVFormat() {
            string retString = "\"" +
                   m_dateTime + "\",\"" +
                   m_info + "\",\"" +
                   m_priority + "\"";

            return retString;
        }
    }
}
<file_sep>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace OCLogInterpreter
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        LogFile lf;
        Microsoft.Win32.OpenFileDialog ofd;
        Microsoft.Win32.SaveFileDialog sfd;

        public MainWindow()
        {
            InitializeComponent();
            lf = new LogFile();
            ofd = new Microsoft.Win32.OpenFileDialog();
            sfd = new Microsoft.Win32.SaveFileDialog();

            EntriesView.ItemsSource = lf.m_entryList;
            PriorityFilterDD.ItemsSource = lf.m_listOfPriorities;
        }

        private void OpenLogFile(object sender, RoutedEventArgs e)
        {
            ofd.DefaultExt = ".log";
            ofd.Filter = "OpenComputers Log Files (.log)|*.log";
            bool? result = ofd.ShowDialog();

            if ( result == true )
            {
                lf.loadFromFile(ofd.FileName);
            }
            else
            {
                MessageBox.Show("Error opening file!");
            }

            refreshAllItems();
        }

        private void refreshAllItems()
        {
            EntriesView.Items.Refresh();
            PriorityFilterDD.Items.Refresh();
        }
        
        private void EntriesView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Entry selectedEntry = (Entry) EntriesView.SelectedItem;

            if (selectedEntry != null)
            {
                SelTimeDateLab.Content = "Date/Time: " + selectedEntry.m_dateTime;
                SelPriorityLab.Content = "Priority: " + selectedEntry.m_priority;
                SelInfoTB.Text = selectedEntry.m_info;
            }
        }

        private void RenewFilter(object sender, RoutedEventArgs e)
        {
            if (FilterCB != null)
            {
                if (FilterCB.IsChecked == true)
                {
                    EntriesView.ItemsSource = lf.filterEntries(PriorityFilterDD.Text, DateFilterTB.Text);
                }
                else
                {
                    EntriesView.ItemsSource = lf.m_entryList;
                }

                refreshAllItems();
            }
        }

        private void PriorityFilterDD_DropDownClosed(object sender, EventArgs e)
        {
            RenewFilter( sender, null );
        }

        private void ExportLogFile(object sender, RoutedEventArgs e)
        {
            sfd.DefaultExt = ".csv";
            sfd.Filter = "Comma Seperated Values (.csv)|*.csv";
            bool? result = sfd.ShowDialog();

            if (result == true)
            {
                lf.exportAsCSV(sfd.FileName);
            }
            else
            {
                MessageBox.Show("Error saving file!");
            }

        }

    }
}
<file_sep># OCLOGAPI
Creates log files in opencomputers

Included:
	The API
	An interpreter for log files ( allows filtration and views in a nice little table )
	An example program for creation ( test.lua )
	An example program for reading ( testr.lua )
	
Documentation is included inside the logapi.lua file.

WPF interpreter executable located at: \OCLOGAPI\OCLogInterpreter\OCLogInterpreter\bin\Debug\OCLogInterpreter.exe<file_sep>local fs = require( "filesystem" )
local term = require( "term" )

--Container

local logContainerMeta = { }

logContainerMeta.__index = logContainerMeta

function logContainer( inPath ) -- Creates a log container ( sort of a massive list for entries ).
	slc = {
		path = inPath,
		entries = { }
	}
	setmetatable( slc, logContainerMeta )
	
	if ( fs.exists( inPath ) ) then
		slc:loadFrom( inPath )
	end
	
	return slc
end

function logContainerMeta:addEntry( newEntry, append ) -- Adds an entry "object" to the specified container.
	table.insert( self.entries, newEntry )
	if ( append ) then
		file = io.open( self.path, "a" )
		file:write( newEntry:serialize( ), "\n" )
		file:flush( )
		file:close( )
	end
end

-- Looks through container and returns a new table of entries that are matching the filter.

function logContainerMeta:findEntriesByPriority( filterPriority ) 
	retTable = { }
	
	for k, v in ipairs( self.entries ) do
		if ( v.priority == tostring( filterPriority ) ) then
			table.insert( retTable, v )
		end
	end
	
	return retTable
end

-- Looks through container and returns a new table of entries that are matching the filter.
-- Note that the filter can be either dd/mm/yy, hh/mm/ss, or dd/mm/yy hh/mm/ss.

function logContainerMeta:removeEntry( entry ) -- Duplicates not taken into account
	for k, v in ipairs( self.entries ) do
		if ( v:entryUnserialize() == entry:entryUnserialize() ) then
			table.remove( self.entries, k )
			break
		end
	end
end

function logContainerMeta:findEntriesByDateTime( filtertd )
	retTable = { }
	
	for k, v in ipairs( self.entries ) do
		if (
		v.timedatestamp == filtertd or
		string.sub( v.timedatestamp, 1, 8 ) == filtertd or
		string.sub( v.timedatestamp, 10, 18 ) == filtertd
		) then
			table.insert( retTable, v )
		end
	end
	
	return retTable
end

function logContainerMeta:loadFrom( path ) -- Loads an entry list from the specified path
	io.input( path )
	allLines = { }
	for l in io.lines( ) do
		table.insert( allLines, l )
	end
	io.close( )
	for k, v in ipairs( allLines ) do
		self:addEntry( entryUnserialize( v ), false )
	end
end

function logContainerMeta:save( path ) -- Saves the entry list to the specified path
	io.output( path )
	for k, v in ipairs( self.entries ) do
		io.write( v:serialize( ), "\n" )
	end
	io.flush( )
	io.close( )
end

function logContainerMeta:exportCSV( path )
	io.output( path )
	io.write( "Date/Time,Log Info,Priority\n" )
	for k, v in ipairs( self.entries ) do
		io.write( v:serializeCSV( ), "\n" )
	end
	io.flush( )
	io.close( )
end

--Entry

local entryMeta = { }

entryMeta.__index = entryMeta

function entry( intds, inInfo, inPriority ) -- Create new entry "object", intds can be either nil ( get current time ) or you can specify a time, make sure it's in the correct format
	e = {
		timedatestamp = "",
		info = tostring( inInfo ),
		priority = tostring( inPriority )
	}
	
	if ( intds == nil ) then
		e.timedatestamp = tostring( os.date( ) )
	else
		e.timedatestamp = tostring( intds )
	end
	
	setmetatable( e, entryMeta )
	return e
end

function entryUnserialize( entrystring ) -- Takes a string and creates an entry from it
	part = 0
	
	tds = ""
	inf = ""
	pri = ""
	
	for i = 1, #entrystring do
		cchar = string.sub( entrystring, i, i )
		if ( cchar == "|" ) then
			part = part + 1
		else
			if ( cchar ~= "\t" ) then
				if ( part == 1 ) then
					tds = tds .. cchar
				elseif ( part == 2 ) then
					inf = inf .. cchar
				elseif ( part == 3 ) then
					pri = pri .. cchar
				end
			end
			
		end
		
	end
	
	return entry( tds, inf, pri )
	
end

function entryMeta:serialize( ) -- Serializes entry for transmission or storage
	return "|" .. self.timedatestamp .. "|" .. self.info .. "|" .. self.priority .. "|"
end

function entryMeta:serializeCSV( ) -- Serializes entry for transmission or storage
	return "\"" .. self.timedatestamp .. "\",\"" .. self.info .. "\",\"" .. self.priority .. "\""
end
<file_sep>require( "logapi" )
term = require( "term" )

newlog = logContainer( )

newlog:loadFrom("testser.log")

for k, v in ipairs ( newlog.entries ) do
	term.write( v.timedatestamp .. "#" .. v.info .. "#" .. v.priority .. "\n")
end

for k, v in ipairs ( newlog:findEntriesByPriority( "5" ) ) do
	term.write( v:serialize() )
end<file_sep>require( "logapi" )
local comp = require( "component" )

local gpu = comp.gpu

local fs = require( "filesystem" )
local term = require( "term" )
local event = require( "event" )

local tdl = 17
local infl = 60
local pril = 16
local display_amount = 5
local curdisplay = 1

local whitecol = 0xFFFFFF
local blackcol = 0x000000
local selcol = 0x00AA55
local logfilecol = 0x00FFFF

path = "/"

local clog = logContainer( )

gpu.setForeground( whitecol )
gpu.setBackground( blackcol )

function pad( str, lenpad )
	return str .. string.rep( " ", lenpad - #str )
end

function drawHeader( )
	term.write( "|" .. string.rep( "=", tdl ) .. "|" .. string.rep( "=", infl ) .. "|" .. string.rep( "=", pril ) .. "|\n" )
	term.write( "|----Date/Time----|----------------------------Info----------------------------|----Priority----|\n" )
end

function drawEntry( entry )
	i = 1
	while true do
		term.write(
		"|" .. pad( string.sub( entry.timedatestamp, (i*tdl)-(tdl-1), i*tdl ), tdl ) .. 
		"|" .. pad( string.sub( entry.info, (i*infl)-(infl-1), i*infl ), infl ) .. 
		"|" .. pad( string.sub( entry.priority, (i*pril)-(pril-1), i*pril ), pril ) ..
		"|\n")
		
		i = i + 1
		
		if ( ( #entry.timedatestamp < i*tdl ) and ( #entry.info < i*infl ) and ( #entry.priority < i*pril ) ) then
			term.write( "|" .. string.rep( "-", tdl ) .. "|" .. string.rep( "-", infl ) .. "|" .. string.rep( "-", pril ) .. "|\n" )
			break
		end	
	end
end

function interpretelogFile( path )
	clog:loadFrom( path )
	
	shownEntries = clog.entries
	
	while true do
		term.clear( )
		drawHeader( )
		for i = curdisplay, curdisplay + display_amount do
			if ( i > #shownEntries ) then
				break
			end
			drawEntry( shownEntries[ i ] )
		end
		term.write( "|" .. string.rep( "=", tdl ) .. "|" .. string.rep( "=", infl ) .. "|" .. string.rep( "=", pril ) .. "|\n" )
		
		term.write( "Use arrow keyes for navigation\nQ to (Q)uit\nF to (F)ind\nR to (R)eset\nE to (E)xport CSV" ) -- q 16 f 33 d 32 p 25 r 19
		
		ev, addr, ch, co, pl = event.pull( "key_down" )
		
		if ( co == 200 and curdisplay > 1 ) then
			curdisplay = curdisplay - 1
		elseif ( co == 208 and curdisplay < #shownEntries - display_amount ) then
			curdisplay = curdisplay + 1
		elseif ( co == 16 ) then
			term.clear( )
			break
		elseif ( co == 18 ) then
			term.clear( )
			term.write( "Path to export: " )
			expPath = term.read( )
			clog:exportCSV( "/" .. string.sub( expPath, 1, #expPath-1 ) )
		elseif ( co == 19 ) then
			shownEntries = clog.entries
		elseif ( co == 33 ) then
			curdisplay = 1
			while true do
				term.clear()
				term.write( "By (D)ate or by (P)riority?\nQ to (Q)uit\n" )
				ev, addr, ch, co, pl = event.pull( "key_down" )
				if ( co == 16 ) then
					break
				elseif ( co == 32 ) then
					term.write( "Date to filter: " )
					dtf = term.read( )
					shownEntries = clog:findEntriesByDateTime( string.sub( dtf, 1, #dtf-1 ) )
					break
				elseif ( co == 25 ) then
					term.write( "Priority to filter: " )
					ptf = term.read( )
					shownEntries = clog:findEntriesByPriority( string.sub( ptf, 1, #ptf-1 ) )
					break
				end
			end
		end

	end
	
end

function choose( options )
	local sel = 1
	
	while true do
		term.clear( )
		for k, v in ipairs( options ) do
			if ( k == sel ) then
				gpu.setForeground( selcol )
				term.write( v .. " <--\n" )
				gpu.setForeground( whitecol )
			else
				if ( string.sub( v, #v - 3, #v ) == ".log" ) then
					gpu.setForeground( logfilecol )
				end
				term.write( v .. "\n" )
				gpu.setForeground( whitecol )
			end
		end
		
		ev, addr, ch, co, pl = event.pull( "key_down" )
		
		if ( co == 200 ) then -- 200 208 28
			if ( sel > 1 ) then
				sel = sel - 1
			else
				sel = #options
			end
		elseif ( co == 208 ) then
			if ( sel < #options ) then
				sel = sel + 1
			else
				sel = 1
			end
		elseif ( co == 28 ) then
			return options[sel]
		end
		
	end
end

while true do
	dirs = { }
	
	table.insert( dirs, "<<exit>>" )
	table.insert( dirs, "<<root>>" )
	
	for dir in fs.list( path ) do
		table.insert( dirs, dir )
	end
	
	choice = choose( dirs )
	
	if ( choice == "<<root>>" ) then
		path = "/"
	elseif ( choice == "<<exit>>" ) then
		term.clear( )
		break
	else
		newpath = path .. "/" .. choice
		
		term.write( string.sub( newpath, #newpath-4, #newpath ) )

		if ( fs.isDirectory( newpath ) ) then
			path = newpath
		elseif ( string.sub( newpath, #newpath-3, #newpath ) == ".log" ) then
			interpretelogFile( newpath )
		end
	end
end<file_sep>require("logapi")
term = require("term")

newlog = logContainer( )

for i = 1, 10 do
	newlog:addEntry( entry( nil,string.rep( "test" .. i, 20), i + 1 ) )
end

newlog:save("testser.log")