summaryrefslogtreecommitdiff
path: root/core/src/Model/Project.cpp
blob: 9f41d3a23f5edb50491809abebee19e08cee55bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "Project.hpp"

#include "Model/Workflow/Workflow.hpp"
#include "Utils/Macros.hpp"

#include <json/reader.h>
#include <json/value.h>
#include <json/writer.h>
#include <filesystem>
#include <fstream>
#include <stdexcept>
#include <utility>

namespace fs = std::filesystem;

template <class T>
void ReadItemList(ItemList<T>& list, const fs::path& filePath)
{
	std::ifstream ifs(filePath);
	if (ifs) {
		Json::Value root;
		ifs >> root;

		list = ItemList<T>(root);
	}
}

Project::Project(fs::path rootPath)
	: mRootPath{ std::move(rootPath) }
	, mRootPathString{ mRootPath.string() }
	, Database(*this)
{
	// TODO better diagnostic
	const char* kInvalidFormatErr = "Failed to load project: invalid format.";

	std::ifstream ifs(mRootPath / "cplt_project.json");
	if (!ifs) {
		std::string message;
		message += "Failed to load project file at '";
		message += mRootPath.string();
		message += "'.";
		throw std::runtime_error(message);
	}

	{
		Json::Value root;
		ifs >> root;

		const auto& croot = root; // Use const reference so that accessors default to returning a null if not found, instead of silently creating new elements
		if (!croot.isObject()) {
			throw std::runtime_error(kInvalidFormatErr);
		}

		if (auto& name = croot["Name"]; name.isString()) {
			mName = name.asString();
		} else {
			throw std::runtime_error(kInvalidFormatErr);
		}
	}

	auto itemsDir = mRootPath / "items";
	ReadItemList(Products, itemsDir / "products.json");
	ReadItemList(Factories, itemsDir / "factories.json");
	ReadItemList(Customers, itemsDir / "customers.json");
}

Project::Project(fs::path rootPath, std::string name)
	: mRootPath{ std::move(rootPath) }
	, mRootPathString{ mRootPath.string() }
	, mName{ std::move(name) }
	, Database(*this)
{
}

const fs::path& Project::GetPath() const
{
	return mRootPath;
}

const std::string& Project::GetPathString() const
{
	return mRootPathString;
}

fs::path Project::GetDatabasesDirectory() const
{
	return mRootPath / "databases";
}

fs::path Project::GetItemsDirectory() const
{
	return mRootPath / "items";
}

fs::path Project::GetWorkflowsDirectory() const
{
	return mRootPath / "workflows";
}

fs::path Project::GetWorkflowPath(std::string_view name) const
{
	return (mRootPath / "workflows" / name).concat(".cplt-workflow");
}

fs::path Project::GetTemplatesDirectory() const
{
	return mRootPath / "templates";
}

fs::path Project::GetTemplatePath(std::string_view name) const
{
	return (mRootPath / "templates" / name).concat(".cplt-template");
}

const std::string& Project::GetName() const
{
	return mName;
}

void Project::SetName(std::string name)
{
	mName = std::move(name);
}

Json::Value Project::Serialize()
{
	Json::Value root(Json::objectValue);

	root["Name"] = mName;

	return root;
}

template <class T>
static void WriteItemList(ItemList<T>& list, const fs::path& filePath)
{
	std::ofstream ofs(filePath);
	ofs << list.Serialize();
}

void Project::WriteToDisk()
{
	std::ofstream ofs(mRootPath / "cplt_project.json");
	ofs << this->Serialize();

	auto itemsDir = mRootPath / "items";
	fs::create_directories(itemsDir);

	WriteItemList(Products, itemsDir / "products.json");
	WriteItemList(Factories, itemsDir / "factories.json");
	WriteItemList(Customers, itemsDir / "customers.json");
}