#include <vector>
#include <string>

class FormatVisitor: public BaseVisitor {
 public:
    void Visit(const BaseNode* node) override {
        node->Visit(this);
    }

    void Visit(const ClassDeclarationNode* node) override {
        result.push_back(ccc + "class " + node->ClassName() + " {");
        std::vector<BaseNode*> pubFi = node->PublicFields();
        if (!pubFi.empty()) {
          result.push_back(ccc + "  public:");
          auto i = pubFi.begin();
          while (i != pubFi.end()) {
            i[0]->Visit(this);
            i++;
          }
        }
        std::vector<BaseNode*> proFi = node->ProtectedFields();
        if (!proFi.empty()) {
          result.push_back("");
          result.push_back(ccc + "  protected:");
          auto i = proFi.begin();
          while (i != proFi.end()) {
            i[0]->Visit(this);
            i++;
          }
        }
        std::vector<BaseNode*> privaFi = node->PrivateFields();
        if (!privaFi.empty()) {
          result.push_back("");
          result.push_back(ccc + "  private:");
          auto i = privaFi.begin();
          while (i != privaFi.end()) {
            i[0]->Visit(this);
            ccc = "    ";
            i++;
          }
          ccc = "";
        }
        result.push_back(ccc + "};");
    }

    void Visit(const VarDeclarationNode* node) override {
        flag++;
        sss += node->TypeName() + ' ' + node->VarName();
        if (flag == 5) {
          sss = "    " + node->TypeName() + ' ' + node->VarName() + ";";
          result.push_back(sss);
        }
    }

    void Visit(const MethodDeclarationNode* node) override {
        sss = ccc + "    " + node->ReturnTypeName();
        sss += ' ' + node->MethodName() + '(';
        std::vector<BaseNode*> args = node->Arguments();
        auto i = args.begin();
        while (i != args.end()) {
          if (i != args.begin()) {
            sss += ", ";
          }
          i[0]->Visit(this);
          i += 1;
        }
        sss += ");";
        result.push_back(sss);
    }

    const std::vector<std::string>& GetFormattedCode() const {
      return result;
    }

 private:
    std::vector<std::string> result;
    std::string sss;
    std::string ccc;
    int flag = 0;
};