using InABox.Integration.Logikal; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Ofcas.Lk.Api.Client.Core; using Ofcas.Lk.Api.Client.Ui; using Ofcas.Lk.Api.Shared; namespace PRSLogikal { public class LogikalLogArguments { public String Message { get; private set; } public LogikalLogArguments(string message) { Message = message; } } public delegate void LogikalLogEvent(object sender, LogikalLogArguments args); public class LogikalServer : IDisposable { public event LogikalLogEvent Log; private void DoLog(String message) => Log?.Invoke(this, new LogikalLogArguments(message)); private IServiceProxyUiResult _proxy; private ICoreObjectResult _login; public IntPtr WindowHandle { get; private set; } private static readonly LogikalErrorResponse NOTCONNECTED = new LogikalErrorResponse() { Status = LogikalStatus.Disconnected, Message = $"LogiKal is not connected" }; private static readonly LogikalErrorResponse NOTLOGGEDIN = new LogikalErrorResponse() { Status = LogikalStatus.NotLoggedIn, Message = $"Not Logged In" }; public LogikalServer(IntPtr windowHandle) { WindowHandle = windowHandle; } public LogikalResponse Connect(LogikalConnectRequest request) { if (_proxy != null) return new LogikalConnectResponse(); var _p = ServiceProxyUiFactory.CreateServiceProxy(request.Path, "ERP"); var _status = _p.ServiceProxyUi.Start(); if (_status.OperationCode != OperationCode.Accepted) { return new LogikalErrorResponse() { Status = LogikalStatus.CannotConnect, Message = $"Unable to connect to LogiKal at [{request.Path}]: {_status}" }; } _proxy = _p; return new LogikalConnectResponse(); } public LogikalResponse Disconnect() { if (_login != null) Logout(); if (_proxy != null) { _proxy.ServiceProxyUi.Stop(); _proxy.Dispose(); } _proxy = null; return new LogikalDisconnectResponse(); } private void DoOnDisconnecting() { } public LogikalResponse Login(LogikalLoginRequest request) { Dictionary _parameters = new Dictionary() { { WellKnownParameterKey.Login.ProgramMode, "erp" }, { WellKnownParameterKey.Login.ApplicationHandle, WindowHandle }, //{ WellKnownParameterKey.Login.UserName, username }, //{ WellKnownParameterKey.Login.Password, password }, { WellKnownParameterKey.Login.EnableEventSynchronization, true }, }; if (_proxy == null) return NOTCONNECTED; if (_login != null) return new LogikalLoginResponse(); var _check = _proxy.ServiceProxyUi.CanLogin(_parameters); if (!_check.CanExecute) { return new LogikalErrorResponse() { Status = LogikalStatus.Restricted, Message = $"Login not allowed: {_check}!" }; } try { var _l = _proxy.ServiceProxyUi.Login(_parameters); if (_l.OperationCode != OperationCode.Accepted) { _login = null; return new LogikalErrorResponse() { Status = LogikalStatus.Failed, Message = $"Login failed: {_l}" }; } else { _login = _l; return new LogikalLoginResponse(); } } catch (Exception e) { return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"{e.Message}\n{e.StackTrace}" }; } } public LogikalResponse Logout() { if (_login != null) _login.Dispose(); _login = null; return new LogikalLogoutResponse(); } public bool IsLoggedIn() => _login != null; private void GetProjectCentres(ICoreObjectResult center, List results) { var _projectresults = new List(); IList _projects = center.CoreObject.ChildrenInfos; foreach (var _project in _projects) { var _summary = new LogikalProject(); PopulateProject(_project, _summary); _projectresults.Add(_summary); } var _result = new LogikalProjectCentre() { ID = center.CoreObject.ProjectCenterContainer.Id, Name = center.CoreObject.Parent != null ? center.CoreObject.Info.DirectoryName : "Project Center", ParentID = center.CoreObject.Parent != null ? center.CoreObject.Parent.ProjectCenterContainer.Id : Guid.Empty, Projects = _projectresults.ToArray() }; results.Add(_result); var _children = center.CoreObject.ProjectCenterContainer.GetChildren().CoreObjectResults; foreach (var _child in _children) GetProjectCentres(_child, results); } private void PopulateProject(IBaseProjectInfo source, ILogikalProject target) { target.ID = source.Guid; target.Title = source.Name; target.PersonInCharge = source.PersonInCharge; target.Path = source.Path; target.LastUpdated = source.LastChangedDateTime; target.Created = source.CreatedDateTime; target.JobNumber = source.AsProjectInfo().JobNumber; target.OfferNumber = source.AsProjectInfo().OfferNumber; } private List GetProjectCentres() { var _results = new List(); var _info = _login.CoreObject.ProjectCenterInfos.FirstOrDefault(x => x.Type.Id == 0); if (_info != null) { var _center = _login.CoreObject.GetProjectCenter(_info); GetProjectCentres(_center, _results); } return _results; } public LogikalResponse GetProjectCentres(LogikalProjectCentresRequest request) { if (_proxy == null) return NOTCONNECTED; if (_login == null) return NOTLOGGEDIN; var _results = GetProjectCentres(); return new LogikalProjectCentresResponse() { ProjectCentres = _results.ToArray() }; } public LogikalResponse GetProjects(LogikalProjectsRequest request) { if (_proxy == null) return NOTCONNECTED; if (_login == null) return NOTLOGGEDIN; List _results = new List(); var _centres = GetProjectCentres(); foreach (var _centre in _centres) { var _projects = _centre.Projects.Where(x => string.IsNullOrWhiteSpace(request.JobNumber) || string.Equals(x.JobNumber, request.JobNumber)); _results.AddRange(_projects); } return new LogikalProjectsResponse() { Projects = _results.ToArray() }; } public LogikalResponse GetProject(LogikalProjectRequest request) { if (_proxy == null) return NOTCONNECTED; if (_login == null) return NOTLOGGEDIN; var _project = _login.CoreObject.GetProjectByGuid(request.ProjectID); if (_project == null) return new LogikalErrorResponse() { Status = LogikalStatus.InvalidProjectID, Message = $"Cannot Load Project {request.ProjectID}" }; var response = new LogikalProjectResponse(); PopulateProject(_project.CoreObject.Info, response.Project); return response; } public LogikalResponse GetPhases(LogikalPhasesRequest request) { if (_proxy == null) return NOTCONNECTED; if (_login == null) return NOTLOGGEDIN; var _project = _login.CoreObject.GetProjectByGuid(request.ProjectID); if (_project == null) return new LogikalErrorResponse() { Status = LogikalStatus.InvalidProjectID, Message = $"Cannot Load Project {request.ProjectID}" }; List _results = new List(); var _phases = _project.CoreObject.GetChildren().CoreObjectResults; foreach (ICoreObjectResult _phase in _phases) { var _result = new LogikalPhase() { ID = _phase.CoreObject.Info.Name, Title = string.IsNullOrWhiteSpace(_phase.CoreObject.Info.Name) ? "Default Phase" : _phase.CoreObject.Info.Name }; _results.Add(_result); } return new LogikalPhasesResponse() { Phases = _results.ToArray() }; } public LogikalResponse GetElevationSummaries(LogikalElevationSummaryRequest request) { if (_proxy == null) return NOTCONNECTED; if (_login == null) return NOTLOGGEDIN; var _results = new List(); var _project = _login.CoreObject.GetProjectByGuid(request.ProjectID); if (_project == null) return new LogikalErrorResponse() { Status = LogikalStatus.InvalidProjectID, Message = $"Cannot Load Project {request.ProjectID}" }; var _phases = _project.CoreObject.GetChildren().CoreObjectResults; var _phase = _phases.FirstOrDefault(x => x.CoreObject.Info.Name == request.Phase); if (_phase == null) return new LogikalErrorResponse() { Status = LogikalStatus.InvalidPhaseID, Message = $"Cannot find phase [{request.Phase}] within project [{request.ProjectID}]" }; var _elevations = _phase.CoreObject.GetChildren().CoreObjectResults; foreach (var _elevation in _elevations) { if (!_elevation.CoreObject.Info.IsInRecycleBin) { var _result = new LogikalElevationSummary(); PopulateElevation(_elevation.CoreObject, _result); _results.Add(_result); } } return new LogikalElevationSummaryResponse() { Elevations = _results.ToArray() }; } private void PopulateElevation(IElevation source, ILogikalElevationSummary target) { target.ID = source.Info.Guid; target.Name = source.Info.Name; target.Description = source.Info.SystemDescription; target.Size = source.Info.Size; using (var ms = new MemoryStream()) { IStreamResult thumbnail = source.GetThumbnail(new Dictionary() { }); thumbnail.Stream.CopyTo(ms); target.Thumbnail = ms.GetBuffer(); } } public LogikalResponse GetBillOfMaterials(LogikalBOMRequest request) { if (_proxy == null) return NOTCONNECTED; if (_login == null) return NOTLOGGEDIN; var _project = _login.CoreObject.GetProjectByGuid(request.ProjectID); if (_project == null) return new LogikalErrorResponse() { Status = LogikalStatus.InvalidProjectID, Message = $"Cannot Load Project [{request.ProjectID}]" }; var _elevations = new List(); if (request.ElevationIDs?.Any() == true) { var _phases = _project.CoreObject.GetChildren(); foreach (var _phase in _phases.CoreObjectResults) _elevations.AddRange(_phase.CoreObject.ChildrenInfos.Where(x => request.ElevationIDs.Contains(x.Guid))); } using (IReportItemsResult reportItemsResult = _project.CoreObject.GetReports()) { if (reportItemsResult.OperationCode != OperationCode.Accepted) { return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"Cannot Get Reports for Project!" }; } // Filter available reports for the erp export report item IReportItem reportItem = reportItemsResult.ReportItems.First(rep => (rep.Id == WellKnownReports.Delivery.ErpExport) && (rep.Category.Id == WellKnownReports.Delivery.CategoryId)); // Create parameters for erp export, export format is required, but always sqlite var exportParameters = new Dictionary { { WellKnownParameterKey.Project.Report.ExportFormat, "SQLite" }, }; // Check if report can be exported for the given parameters var operationInfo = _project.CoreObject.CanGetReport(reportItem, _elevations, exportParameters); if (!operationInfo.CanExecute) { return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"Cannot Get Erp Report for Project!" }; } // Run report creation asynchronously - begin method starts the operation in background task using (ISynchronizedOperationResult synchronizedOperationResult = _project.CoreObject.BeginGetReport(reportItem, _elevations, exportParameters)) { var response = new LogikalBOMResponse(); // End method waits for the background operation to complete in separate task using (IStreamResult partsResult = Task.Run(() => _project.CoreObject.EndGetReport(synchronizedOperationResult.SynchronizedOperation)).Result) { Stream exportStream = partsResult.Stream; using (var _ms = new MemoryStream()) { exportStream.CopyTo(_ms); response.BOM.SQLiteData = _ms.GetBuffer(); } } return response; } } } public LogikalResponse GetElevationDetails(LogikalElevationDetailRequest detailRequest) { var _project = _login.CoreObject.GetProjectByGuid(detailRequest.ProjectID); if (_project == null) return new LogikalErrorResponse() { Status = LogikalStatus.InvalidProjectID, Message = $"Cannot Load Project [{detailRequest.ProjectID}]" }; Dictionary> elevations = new Dictionary>(); var _phases = _project.CoreObject.GetChildren().CoreObjectResults; foreach (var id in detailRequest.IDs) { foreach (var _phase in _phases) { var ui = _phase.CoreObject.GetChildren().CoreObjectResults .FirstOrDefault(e => e.CoreObject.Info.Guid == id); if (ui != null) elevations[id] = ui; } if (!elevations.ContainsKey(id)) { return new LogikalErrorResponse() { Status = LogikalStatus.ElevationNotFound, Message = $"Cannot find Elevation [{id}] within project [{detailRequest.ProjectID}]" }; } } try { List results = new List(); var response = new LogikalElevationDetailResponse(); foreach (var id in elevations.Keys) { var _elevation = elevations[id]; LogikalElevationDetail newel = new LogikalElevationDetail(); PopulateElevation(_elevation.CoreObject, newel); var dxf = ElevationDetails(detailRequest, _elevation, id, newel, detailRequest.DrawingFormat, detailRequest.DrawingView, detailRequest.DrawingType); if (dxf != null) return dxf; results.Add(newel); } response.Elevations = results; return response; } catch (Exception e) { return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"{e.Message}\n\n{e.StackTrace}" }; } } private LogikalResponse ElevationDetails(LogikalElevationDetailRequest detailRequest, ICoreObjectResult _elevation, Guid id, LogikalElevationDetail newel, LogikalDrawingFormat format, LogikalDrawingView view, LogikalDrawingType type) { // Setup parameters for export of the elevation drawing var sectionDrawingParameters = new Dictionary { { WellKnownParameterKey.Elevation.Drawing.Format, format == LogikalDrawingFormat.DXF ? ElevationDrawingFormat.DXF : ElevationDrawingFormat.PNG }, { WellKnownParameterKey.Elevation.Drawing.View, view == LogikalDrawingView.Exterior ? View.Exterior : View.Interior }, { WellKnownParameterKey.Elevation.Drawing.Type, type == LogikalDrawingType.Explosion ? ElevationDrawingType.Explosion : type == LogikalDrawingType.Section ? ElevationDrawingType.Section : type == LogikalDrawingType.Elevation ? ElevationDrawingType.Elevation : type == LogikalDrawingType.ElevationWithSectionLines ? ElevationDrawingType.ElevationWithSectionLines : ElevationDrawingType.SectionLine }, { WellKnownParameterKey.Elevation.Drawing.DxfVersion, DxfVersion.Acad2013 }, { WellKnownParameterKey.Elevation.Drawing.ShowDescription, true }, { WellKnownParameterKey.Elevation.Drawing.ShowDimensions, true }, { WellKnownParameterKey.Elevation.Drawing.Scale, 1.0 }, }; // Check if the drawing can be exported for the elevation with the given parameters if (!_elevation.CoreObject.CanGetDrawing(sectionDrawingParameters).CanExecute) { return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"GetDrawing() not permitted for Elevation [{id}]" }; } // Generate drawing for the elevation with the given parameters using (IDrawingResult drawingResult = _elevation.CoreObject.GetDrawing(sectionDrawingParameters)) { Stream exportStream = drawingResult.Stream; using (var _ms = new MemoryStream()) { exportStream.CopyTo(_ms); newel.Drawing = _ms.GetBuffer(); } } using (IStreamResult partsResult = _elevation.CoreObject.GetPartsList()) { Stream exportStream = partsResult.Stream; using (var _ms = new MemoryStream()) { exportStream.CopyTo(_ms); newel.SQLiteData = _ms.GetBuffer(); } } return null; } public void Dispose() { Disconnect(); } } }