#!/usr/bin/perl -w

use Test::Simple tests => 24;

sub quote_singlequote {
  my (%args) = @_;
  my @all;
  foreach my $char (split //, $args{Thing}) {
    if ($char eq "'") {
      push @all, "\\'";
    } elsif ($char eq '\\') {
      push @all, '\\\\';
    } else {
      push @all, $char;
    }
  }
  my $res = join('',@all);
  if ($args{DelimitingQuotes}) {
    return "'$res'";
  } else {
    return $res;
  }
}

sub quote_doublequote {
  my (%args) = @_;
  my @all;
  foreach my $char (split //, $args{Thing}) {
    if ($char eq '"') {
      push @all, '\\"';
    } elsif ($char eq '\\') {
      push @all, '\\\\';
    } else {
      push @all, $char;
    }
  }
  my $res = join('',@all);
  if ($args{DelimitingQuotes}) {
    return '"'.$res.'"';
  } else {
    return $res;
  }
}

sub dequote_singlequote {
  my (%args) = @_;
  my @dequotedall;
  my $state = 'beginning';
  foreach my $char (split //, $args{Thing}) {
    if ($char eq "'") {
      if ($state eq 'beginning') {
	if ($args{DelimitingQuotes}) {
	  $state = 'open';
	} else {
	  # throw error
	}
      } elsif ($state eq 'open') {
	if ($args{DelimitingQuotes}) {
	  $state = 'ending';
	} else {
	  # throw error
	}
      } elsif ($state eq 'quoting') {
	$state = 'quoted';
	push @dequotedall, "'";
      } elsif ($state eq 'ending') {
	# throw error
      }
    } elsif ($char eq '\\') {
      if ($state eq 'beginning') {
	if ($args{DelimitingQuotes}) {
	  # throw error
	} else {
	  $state = 'quoting';
	}
      } elsif ($state eq 'open') {
	$state = 'quoting';
      } elsif ($state eq 'quoting') {
	$state = 'open';
	push @dequotedall, '\\';
      } elsif ($state eq 'ending') {
	# throw error
      }
    } else {
      push @dequotedall, $char;
    }
  }
  return join('',@dequotedall);
}

sub dequote_doublequote {
  my (%args) = @_;
  my @dequotedall;
  my $state = 'beginning';
  foreach my $char (split //, $args{Thing}) {
    if ($char eq '"') {
      if ($state eq 'beginning') {
	if ($args{DelimitingQuotes}) {
	  $state = 'open';
	} else {
	  # throw error
	}
      } elsif ($state eq 'open') {
	if ($args{DelimitingQuotes}) {
	  $state = 'ending';
	} else {
	  # throw error
	}
      } elsif ($state eq 'quoting') {
	$state = 'open';
	push @dequotedall, '"';
      } elsif ($state eq 'ending') {
	# throw error
      }
    } elsif ($char eq '\\') {
      if ($state eq 'beginning') {
	if ($args{DelimitingQuotes}) {
	  # throw error
	} else {
	  $state = 'quoting';
	}
      } elsif ($state eq 'open') {
	$state = 'quoting';
      } elsif ($state eq 'quoting') {
	$state = 'open';
	push @dequotedall, '\\';
      } elsif ($state eq 'ending') {
	# throw error
      }
    } else {
      push @dequotedall, $char;
    }
  }
  return join('',@dequotedall);
}

sub test {
  my (%args) = @_;
  test_quote_singlequote('hi' => 'hi');
  test_quote_singlequote("'" => "\\'");
  test_quote_singlequote("\\'" => "\\\\\\'");

  test_quote_doublequote('hi' => 'hi');
  test_quote_doublequote('"' => '\\"');
  test_quote_doublequote('\\"' => '\\\\\\"');

  test_dequote_singlequote('hi' => 'hi');
  test_dequote_singlequote("\\'" => "'");
  test_dequote_singlequote("\\\\\\'" => "\\'");

  test_dequote_doublequote('hi' => 'hi');
  test_dequote_doublequote('\\"' => '"');
  test_dequote_doublequote('\\\\\\"' => '\\"');


  test_quote_singlequote('hi' => "'hi'",1);
  test_quote_singlequote("'" => "'\\''",1);
  test_quote_singlequote("\\'" => "'\\\\\\''",1);

  test_quote_doublequote('hi' => '"hi"',1);
  test_quote_doublequote('"' => '"\\""',1);
  test_quote_doublequote('\\"' => '"\\\\\\""',1);

  test_dequote_singlequote("'hi'" => 'hi',1);
  test_dequote_singlequote("'\\''" => "'",1);
  test_dequote_singlequote("'\\\\\\''" => "\\'",1);

  test_dequote_doublequote('"hi"' => 'hi',1);
  test_dequote_doublequote('"\\""' => '"',1);
  test_dequote_doublequote('"\\\\\\""' => '\\"',1);

}

sub test_quote_singlequote {
  my ($key,$value,$opt) = @_;
  my ($a,$b) = (quote_singlequote(Thing => $key, DelimitingQuotes => $opt),$value);
  ok($a eq $b, 'Success: quote_singlequote on '.$key.' evaluates to '.$a.' when it should be '.$b );
}

sub test_quote_doublequote {
  my ($key,$value,$opt) = @_;
  my ($a,$b) = (quote_doublequote(Thing => $key, DelimitingQuotes => $opt),$value);
  ok($a eq $b, 'Success: quote_doublequote on '.$key.' evaluates to '.$a.' when it should be '.$b );
}

sub test_dequote_singlequote {
  my ($key,$value,$opt) = @_;
  my ($a,$b) = (dequote_singlequote(Thing => $key, DelimitingQuotes => $opt),$value);
  ok($a eq $b, 'Success: dequote_singlequote on '.$key.' evaluates to '.$a.' when it should be '.$b );
}

sub test_dequote_doublequote {
  my ($key,$value,$opt) = @_;
  my ($a,$b) = (dequote_doublequote(Thing => $key, DelimitingQuotes => $opt),$value);
  ok($a eq $b, 'Success: dequote_doublequote on '.$key.' evaluates to '.$a.' when it should be '.$b );
}

test();
