#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

#define tf(IsTrue) ((IsTrue) ? "True" : "False")

int main() {
   uCalc uc;
   // Rosetta Stone
   // Pseudocode translation to C++, C#, or VB
   // This shows only in C++



   //This shows in C++ and VB, not C#
   //This shows in C++ and C#, not Vb
   //The c tag is the same as the NotVB tag
   // Tags (c, cpp, cs, vb, NotCpp, NotCs, NotVb, etc.,) are not case-sensitive

   cout << "w() prints text without ";
   cout << "a new line at the end.";
   cout << endl; // Moves to a new line
   cout << "wl() prints a line, ending with a newline." << endl;
   cout << "Line 2" << endl;
   cout << "Line 3" << endl;
   cout << 123 << " multiple args " << "for wl()" << endl;
   cout << "multiple " << "args " << "for w() too";
   cout << "" << endl;

   auto t = uc.NewTransformer();
   // Property setter syntax: @ followed by property name and value in parenthesis
   t.Description("Some description goes here");

   // Property getter sytanx: @ followed by property name, and empty parenthesis
   cout << t.Description() << endl;

   // Each property has an alternative getter and setter function syntax
   // with the Get or Set prefix like this:
   t.SetDescription("A new description");
   cout << t.GetDescription() << endl;

   // Using the alternative function syntax for a property can be useful when chaining calls
   // I use the c tag for the sake of VB that wants everything on the same line.
   t.SetText("Some Text").SetDescription("Some description")
   .FromTo("Text", "String").SetCaseSensitive(true).SetMinimum(1).SetMaximum(5)
   .GetParentTransformer().Transform();
   cout << t.Text() << endl;

   // For compatibility across C++, C#, and VB, use the Verbatim tag for multi-line
   // strings.  Do not use escapes or specialized double-quote syntax in a string.
   auto MyString = R"(Here is some "quoted" text on one line
And some random text on another line)";
   cout << MyString << endl;

   // Use this syntax to define a variable with a uCalc-related type
   // Either with or without an initial value
   uCalc::String MyStringA;
   uCalc::String MyStringB = "This is some text.";
   MyStringA = MyStringB.Text() + " Some more text";
   cout << MyStringA.Text() << endl;

   // For simple types not belonging to uCalc, use this C#-like notation instead:

   auto OtherString = "Some other string ";
   auto MyNumber = 12345;
   cout << OtherString << MyNumber << endl;

   // Another way to define a new variable (with a uCalc type) is with the more
   // flexible New.  Use this especially if you need to use arguments:

   uCalc::Item MyVar("Variable: x = 123");
   uCalc::Item MyFunc(uc, "Function: f(x) = x^2");
   cout << uCalc::DefaultInstance().Eval("x") << endl;
   cout << uc.Eval("f(5)") << endl;

   // To define a uCalc object that gets released when the object goes out of scope, do:
   {
      uCalc::Transformer tr;
      tr.Owned(); // Causes tr to be released when it goes out of scope
      tr.FromTo("This", "That");
      cout << tr.Transform("This car").Text() << endl;
      // To accomodate other languages besides C#, you must explicitely end the using block
   }

   // Use the C++ style to_string to convert a value to a string
   cout << "Value: " + to_string(100 + 25) << endl;

   // Always use the C++ double colon, ::, for scope resolution
   // (it gets translated to a dot, ., in C# and VB
   auto MyTokens = t.Tokens();
   cout << uc.DataTypeOf(BuiltInType::Float_Double).Name() << endl;

   // Other supported constructs
   for (double x = 1; x <= 10; x++) {
      cout << x << endl;
   }

   for (double x = 1; x <= 10; x = x + 2) {
      cout << x << endl;
   }

   for(auto dType : uc.DataTypes()) {
      cout << dType.Name() << endl;
   }

   auto count = 0;

   while (count <= 5) {
      cout << count << endl;
      count += 1;
   }

   do {
      cout << count << endl;
      count = count + 1;
   } while (count <= 10);

   if (count < 100) {
      cout << "count is less than 100" << endl;
   }

   if (count < 5) {
      // Some lines of code
      cout << "count is less than 5" << endl;
   } else if (count <= 50) {
      // . . .
      cout << "count is less than or equal to 50" << endl;
   } else {
      // More lines of code
      cout << "count is greater than 50" << endl;
   }

   // Declare and initialize a string array
   vector<string> items = {"Apple", "Banana", "Cherry"};

   // Get the size of the array
   count = items.size();
   cout << "Total items: " << count << endl;

   // Access and modify elements
   cout << "First item: " << items[0] << endl;
   items[1] = "Blueberry";

   // Iterate through the array
   auto i = 0;
   do {
      cout << items[i] << endl;
      i = i + 1;
   } while (i < items.size());

   // For proper translation into the 3 supported languages, wrap Boolean values with
   // bool.  When pseudocode contains the bool function, a helper function named tf is
   // inserted towards to the top of the code

   cout << uc.EvalStr("'Cos is a function? '") << tf(uc.ItemOf("Cos").IsProperty(ItemIs::Function)) << endl;
   cout << uc.EvalStr("'Cos is a variable? '") << tf(uc.ItemOf("Cos").IsProperty(ItemIs::Variable)) << endl;
}