/*

CLASS {String_functions|_primary_compiler},
NATIVE, BITWISE :

IMPORT: {System_functions} ;
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AL4Compiler
{
    public class StringFunctions
    {
        /*
        
        //STR DATA|_fake_array[]
        
        FUNCTION Add_trail|ing(
        STR S|ource_str, STR Trail|ing_str) ==> STR, STATIC
        	:
            CASE Ending(S, Trail) ? RESULT = S ==> ;
            RESULT = S Trail .
        */
        public static string Add_trailing(string S, string trailing)
        {
            if (!Ending(S, trailing))
                return S + trailing;
            return S;
        }

        /*
        
        FUNCTION Trailing_slash(
        STR P|ath_input) ==> STR, STATIC
        	:
            CASE P == "" ? ==> ;     
            RESULT = Add_trail(P, "\") .

		FUN Remove_starting(
			STR S|ource_string, STR T|o_remove) ==> STR
			:
		    -------------------------------- 'If S is ending by T, remove it'
		    RESULT = S
		    CASE Starting(S, T) ? RESULT = S.[T.Len TO *] ; .
		    
        FUN Remove_trailing(
        STR S|ource_string, STR T|o_remove) ==> STR, STATIC
            :
            RESULT = S
            CASE Ending(S, T) ? RESULT = S[0 TO *-T.Len] ; .

        TEST trailing :
             ASSERT "".Trailing_slash == ""
             ASSERT "x".Trailing_slash == "x\"
             ASSERT "x\".Trailing_slash == "x\"
             ASSERT Remove_trailing("x\", "\") == "x" 
             .
             
		FUN Exclude|_substring(
        STR S|tring_wher_exclude,
        STR W|hat_to_exclude) ==> STR
        	:
        	RESULT = S
			FOR i|dummy IN [RESULT.Len - 1 DOWNTO 0] :
			    INT pos|ition_of_W = RESULT.Find(W)
			    CASE pos < 0 ? ==> ;
				RESULT = RESULT[0 TO pos-1] RESULT[pos + W.Len TO *] ; .
				
        FUN Remove_all(
        STR S|tring_wher_exclude,
        STR W|hat_to_exclude) ==> STR
        	: RESULT = Exclude(S, W) .     
        	
                
        */
        public static string Trailing_slash(string P)
        {
            return Add_trailing(P, "\\");
        }

        /*
        
        FUNCTION Starting|_with_string(
        STR S|ource_s, STR E|nding_str) ==> BOOL, STATIC
        	:
            RESULT = S[0 TO E.Len-1] == E .
        
        FUNCTION Ending|_with_string(
        STR S|ource_s, STR E|nding_str) ==> BOOL, STATIC
        	:
            RESULT = S[*-E.Len+1 TO *] == E .
            
        TEST starting_ending :
             ASSERT Starting("abc", "a")
             ASSERT Ending("abc", "c") .
			 
        FUNCTION Find_last(
        STR S|tring_where_find, STR W|hat_find ) ==> INT, STATIC
        	:
            ----------------------------------- 'if not found return -1'
            INT len1|_gth = W.Len - 1
            FOR i IN [S.Len-W.Len DOWNTO 0] :
                CASE S[i TO i + len1] == W ? RESULT = i ==> ;
            ;
            RESULT = -1 .
            
        TEST of_Find_last :
             ASSERT Find_last("_", "_") == 0
             ASSERT Find_last("1_1", "1") == 2
             ASSERT Find_last(".", "-") == -1
             ASSERT Find_last("+++", "") == 3 .			

        FUNCTION Find_from(STR S|tring_where_find, INT From|_index,
        	STR W|hat_find ) ==> INT
        	:
            ----------------------------------- 'if not found return -1'
            INT len1|_gth = W.Len - 1
            FOR i IN [From TO S.Len-W.Len] :
                CASE S[i TO i + len1] == W ? RESULT = i ==> ;
            ;
            RESULT = -1 .
            
        TEST of_Find_from :
             ASSERT Find_from("_", 1, "_") == -1
             ASSERT Find_from("1_1", 1, "1") == 2
             ASSERT Find_from(".", 0, "-") == -1 .             
        */
        public static bool Ending(string S, string ending)
        {
            return S.Length - ending.Length >= 0 && 
                S.Substring(S.Length - ending.Length, ending.Length) == ending;
        }

        /*
        
        FUNCTION Char|acter(
        INT I|nteger_code) ==> STR, STATIC, NATIVE :
            "return " #QU #QU " + (char)X_I;" .
            
        FUNCTION Ord|er_of_char(
        STR Ch|aracter) ==> INT, STATIC, NATIVE :
            "return (int)((X_Ch + (char)0)[0]);" .
            
        FUNCTION Upper|_case(
        STR S|ource_str) ==> STR, STATIC, NATIVE :
            "return X_S.ToUpper();" .

        FUNCTION Lower|_case(
        STR S|ource_str) ==> STR, STATIC, NATIVE :
            "return X_S.ToLower();" .

        FUNCTION Trim|_both_sides(
        STR S|ource_str) ==> STR, STATIC :
            CASE S==#0 ? RESULT = "" ==> ;
            RESULT = TrimR(TrimL(S)) .

        FUNCTION TrimR|ight(
        STR S|ource_str) ==> STR, STATIC, NATIVE :
            "return X_S.TrimEnd();" .

        FUNCTION TrimL|eft(
        STR S|ource_str) ==> STR, STATIC, NATIVE :
            "return X_S.TrimStart();" .
        */
        public static string TrimL(string S)
        {
            return S.TrimStart();
        }

        /*
        
        FUN Split|_string(
        STR Dest|ination_array[], STR S|tring_to_split,
        STR By|_pattern), STATIC, NATIVE :
            @"string[] x = X_S.Split(new string[]{X_By}, "
             "    StringSplitOptions.None);"
             "foreach (string s in x)"
             "    X_Dest.Add(s);" .
             
		FUN Merge|_strings(
			STR S|trings_to_merge[], STR Sep|arator) ==> STR
			:
			RESULT = S[0]
			FOR i IN [1 TO S[].Count-1] :
			    RESULT << Sep S[i] ; .
			    
FUN Count_char|s(
STR S|tring_in, STR C|har_to_count) ==> INT
	:
	FOR i IN [0 TO S.Len-1] :
	    CASE S[i] == C ? RESULT += 1 ;
	; .
	    
			    
             

        FUN Replace|_symbol(
        STR S|ource_string,
        STR F|rom_symbol,
        STR T|o_symbol) ==> STR, STATIC
        	:
            RESULT = S
            INT i|index_of_symbol = S.Find(F)
            CASE i < 0 ? ==> ;
            RESULT = S[0 TO i-1] T S[i+F.Len TO *] .
            
FUN Replace_all(
STR S|ource_string, STR F|rom_symbol, STR T|o_symbol) ==> STR
    :
    RESULT = S
    FOR dummy IN [0 TO S.Len-1] :
        STR bef|ore_replace = RESULT
        RESULT = Replace(RESULT, F, T)
        CASE RESULT == bef ? ==> ;
    ; .
            

        TEST replace_symbol :
             ASSERT Replace("x", "x", "y") == "y"
             ASSERT Replace("x", "y", "z") == "x" .
             
		FUNCTION Repeat|_string(
			STR What|_to_repeat, INT Count|_spaces) ==> STR
			:
			FOR i|dummy IN [1 TO Count]: RESULT << What ; .             
             
        FUN Hex|_from_integer(
        INT N|umber_to_hex, INT Min|imum_digits) ==> STR
        	:
            ------------------------ 'Number to hexadecimal, without 0x prefix'
            INT n|umber_to_hex = N
            FOR i|dummy IN [1 TO 20] :
                CASE n == 0 ? BREAK i ;
                INT low|_digit = n & 0xF
                n = n * 16
                CASE low < 10 ? RESULT = (("0").Ord + low).Char RESULT 
                ELSE RESULT = (("A").Ord + low - 10).Char RESULT ;
            ;
            FOR i IN [RESULT.Len + 1 TO Min] :
                RESULT = "0" RESULT ; .
        (***********************/

    }
}
/*
END
*/

