#!/usr/bin/perl -w

use strict;

# Input file. Example: tests/features/zanshin/features/inbox/inbox-display-test.feature
my $file = $ARGV[0];
$file =~ s,\./,,;
open(my $FILE, "<", $file) || die;

# Output file. Example: tests/features/inbox/inboxdisplaytestfeature.cpp
my $outfile = $file;
$outfile =~ s,zanshin/features/,,;
$outfile =~ s/[\.\-]//g;
$outfile .= ".cpp";
open(my $OUT, ">", $outfile) || die "Cannot open $outfile for writing";

# Base name, e.g. inbox-display-test
my $basename = $file;
$basename =~ s,.*/,,;
$basename =~ s,\.feature$,,;

# Classname. Example: InboxDisplayTest
my $classname = $basename;
$classname =~ s/(\w)(\w*)/\U$1\L$2/g; #https://www.perlmonks.org/?node_id=471292
$classname =~ s/[\.\-]//g;
$classname .= "Feature";

# Moc file
my $mocfile = $outfile;
$mocfile =~ s,.*/,,;
$mocfile =~ s/cpp$/moc/;

# CMake target
my $target = $mocfile;
$target =~ s/\.moc$//;

print "$file => $outfile with $classname\n";

print $OUT "/* This file is part of Zanshin

   Copyright 2019 Kevin Ottens <ervin\@kde.org>
   Copyright 2019 David Faure <faure\@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include <testlib/qtest_zanshin.h>
#include <featurelib/zanshincontext.h>

using namespace Testlib;

";

my $state_feature = 1;
my $state_scenario = 2;
my $state_table_firstline = 3;
my $state_table = 4;
my $state_simple_table_firstline = 5;
my $state_simple_table = 6;
my $state = 0;

while (<$FILE>) {
    if ($state == 0 && /Feature:/) {
        $state = $state_feature;
    }
    if (my ($scenario_name) = /^\s*Scenario(?: Outline)?: (.*)/) {
        $scenario_name =~ s/[ ']/_/g;
        $scenario_name =~ s/,//g;

        if ($state == $state_feature) {
            # first scenario, generate class
            print $OUT "class $classname : public QObject\n{\n    Q_OBJECT\nprivate slots:\n";
        } else {
            # close up previous scenario
            print $OUT "    }\n\n";
        }
        print $OUT "    void ${scenario_name}()\n";
        print $OUT "    {\n";
        print $OUT "        ZANSHIN_CONTEXT;\n";
        $state = $state_scenario;
        next;
    }
    if ($state == $state_table && !/\|/) {
        $state = $state_scenario;
        print $OUT "                             }
                         }));\n";
    } elsif ($state == $state_simple_table && !/\|/) {
        $state = $state_scenario;
        print $OUT "                             }));\n";
    }

    if ($state == $state_feature && !/^\s*$/) {
        print $OUT "// " . $_;
    } elsif ($state == $state_scenario) {
        if (/Then the list is/) {
            $state = $state_table_firstline;
            print $OUT "        Then(the_list_is({\n";
        } elsif (my ($type, $phrase) = /\s*(\w+) (.*)/) {  # e.g. "When I list the items" => $type is "When"
            my $func = $phrase;
            my $arg = "";
            my $arg2 = "";
            my $arg3 = "";
            $arg = $1 if ($func =~ s/the (\"[^\"]*\") page/the_page/);
            if ($func =~ s/there is an item named \"(.*)\" in the central list/there_is_an_item_in_the_central_list/) {
                $arg = $1;
                $arg =~ s/\"/\\\"/g;
                $arg = "\"$arg\"";
            }
            $arg = $1 if ($func =~ s/I rename the item to (\"(.*)\")/I_rename_the_item/);
            $arg = $1 if ($func =~ s/there is an item named (\"(.*)\") in the available data sources/there_is_an_item_in_the_available_data_sources/);
            $arg = $1 if ($func =~ s/there is an item named (\"[^\"]*\")/there_is_an_item/);
            $arg = $1 if ($func =~ s/the default data source is (\"[^\"]*\")/the_default_data_source_is/);
            $arg = $1 if ($func =~ s/the user changes the default data source to (\"[^\"]*\")/I_change_the_default_data_source/);
            $arg = $1 if ($func =~ s/the list does not contain (\"[^\"]*\")/the_list_does_not_contain/);
            $arg = $1 if ($func =~ s/the list contains (\"[^\"]*\")/the_list_contains/);
            $arg = $1 if (/drop/ && $func =~ s/on (\"[^\"]*\") in the (.*) list/on_the_$2_list/);
            #print STDERR "FUNC=$func\n";
            if ($func =~ s/I add a \"(.*)\" named (\"[^\"]*\")/I_add_a_$1/) {
                $arg = "$2";
            } elsif ($func =~ s/I rename the page named (.*) under (\"[^\"]*\") to (\"[^\"]*\")/I_rename_a_page/) {
                $arg = "$2";
                $arg2 = ", $1";
                $arg3 = ", $3";
            } elsif ($func =~ s/I remove the page named (.*) under (\"[^\"]*\")/I_remove_a_page/) {
                $arg = "$2";
                $arg2 = ", $1";
            } elsif ($func =~ s/I add a project named (.*) in the source named (\"[^\"]*\")/I_add_a_project/) {
                $arg = "$1";
                $arg2 = ", $2";
            } elsif ($func =~ s/I add a child named (.*) under the task named (\"[^\"]*\")/I_add_a_task_child/) {
                $arg = "$1";
                $arg2 = ", $2";
            } elsif ($func =~ s/change the editor (.*) to (\"[^\"]*\")/change_the_editor_field/) {
                $arg = "\"$1\""; # field
                $arg2 = ", $2"; # value
            } elsif ($func =~ s/the editor shows (\"[^\"]*\") as (.*)/the_editor_shows_the_field/) {
                $arg = "\"$2\""; # field
                $arg2 = ", $1"; # expectedValue
            } elsif ($func =~ s/the setting key (\w+) is (\d+)/the_setting_is/) {
                $arg = "\"$1\"";
                $arg2 = ", $2";
            } elsif ($func =~ s/the setting key (\w+) changes to (\d+)/I_change_the_setting/) {
                $arg = "\"$1\"";
                $arg2 = ", $2";
            }
            $func =~ s/ /_/g;
            #print STDERR "FINAL FUNC=$func\n";
            if ($func =~ /contains_items_named/) {
                $func =~ s/://;
                $state = $state_simple_table_firstline;
                print $OUT "        $type(${func}({\n";
            } else {
                print $OUT "        $type(${func}(${arg}${arg2}${arg3}));\n";
            }
        }
    } elsif ($state == $state_table_firstline) {
        my ($item) = /^\s*\| (.*?)\s*\|\s*$/;
        die "Table first item parse error:" . $_ unless defined $item;
        $item =~ s/\s*\|\s*/\", \"/g;
        print $OUT "                             { \"$item\" },\n";
        print $OUT "                             {\n";
        $state = $state_table;
    } elsif ($state == $state_table) {
        my ($item) = /^\s*\| (.*?)\s*\|\s*$/;
        die "Table item parse error:" . $_ unless defined $item;
        $item =~ s/\"/\\\"/g;
        $item =~ s/\s*\|\s*/\", \"/g;
        print $OUT "                                 { \"$item\" },\n";
    } elsif ($state == $state_simple_table_firstline) {
        my ($item) = /^\s*\| (.*?)\s*\|\s*$/;
        die "Simple table first item parse error:" . $_ unless defined $item;
        # we just eat away the useless "display" line.
        die "Unexpected first item in simple table: $item\n" unless $item eq "display";
        $state = $state_simple_table;
    } elsif ($state == $state_simple_table) {
        my ($item) = /^\s*\| (.*?)\s*\|\s*$/;
        die "Simple table item parse error:" . $_ unless defined $item;
        $item =~ s/\"/\\\"/g;
        print $OUT "                                 \"$item\",\n";
    }
}

if ($state == $state_table) {
    print $OUT "                             }
                         }));\n";
}

print $OUT "    }
};

ZANSHIN_TEST_MAIN($classname)

#include \"$mocfile\"
";

close($OUT);
close($FILE);
print STDERR "Add $target to CMakeLists.txt, test compilation. When it works:\n";
print STDERR "git rm $file; git add $outfile\n";
