// RELATED SOFTWARE: Scilab 
// LICENSE   : CeCILL-C : http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
// FUNCTION  : strrand()
// AUTHOR (C): Samuel GOUGEON - private individual
// COPYRIGHT : Samuel GOUGEON - 2015
// RELEASE   : 1.0
// DATE      : 2015-07-28
// DISTRIBUTION: http://fileexchange.scilab.org/toolboxes/367000
// HISTORY   : 
//   1.0 - 2015-07-28: first publication on FileExchange
//
// DISCLAIMER: 
//   This script is provided as is, with NO WARRANTY of any kind.
//   Use it to your own risks & responsability.
//

function T = strrand(L, charsets, newSeed)
//
// Generates random characters, words or texts
// 
//SYNTAX
//     strrand                      // display this help
// T = strrand(L)                   // use default charset 'a-zA-Z0-9' charset
// T = strrand(L, charsets)         // use or add given charsets
// T = strrand(L, charsets, newSeed) // process with a flying seed
//
//PARAMETERS
// L: Single number, or vector, matrix.. of positive integers: 
//    The lengths of random texts to be generated. 
//
// charsets: optional string specifying sets of characters to be used.
//    * Default: 'abcdefghijklmnopqrstuvwxyz0123456789' are used.
//
//    * If the first character of charsets is "+", the default charset
//      is used, and characters or/and classes of characters specified 
//      after the "+" are ADDED to the default charset.
//
//    * Individual characters must be specified at the beginning of 
//      the charsets string. 
//      If any, classes of characters are specified afterwards.
//      The list of classes starts with a ":".
//      The code of each class is prefixed with ":". 
//      Therefore, the name of the first specified class is actually
//      prefixed with "::"
//      Available classes of characters are:
//            :a = "abcdefghijklmnopqrstuvwxyz"
//            :A = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
//            :# = "0123456789"
//          :hex = "0123456789abcdef"
//          :Hex = "0123456789ABCDEF"
//          :#rom= "IVXLCDM" 
//          :xfr = "àâäçéèêëïôöùûü"
//          :xFr = "ÀÂÄÇÉÈÊËÏÔÖÙÛÜ"
//           :ru = "абвгдеёжзийіклмнопрстуфхцчшщъыьѣэюяѳѵ"
//           :Ru = "АБВГДЕЁЖЗИЙІКЛМНОПРСТУФХЦЧШЩЪЫЬѢЭЮЯѲѴ"
//          :xRu = "ѕЅѡѠѥѤѫѪѩѨѭѬѯѮѱѰ"
//           :ja = "あいうえおはひふへほかきくけこまみむめもさしすせそ"+..
//                 "やゆよたちつてとらりるれろなにぬねのわゐんゑを"
//
//    * Statistical frequencies: The average frequency of a character 
//      or of characters of a class in the generated texts is 
//      proportional to the number of times that the character appears 
//      in the whole set of default or/and specified charsets string. 
//      For instance, 'abb' will generate texts made only of 'a' and 'b'
//      with in average twice more 'b' than 'a'.
//
// newSeed: boolean. If %T (true), the seed of the random generator is changed
//      before processing (it is made pointing to the current millisecond). 
//      This option can be used if one wants to avoid generating the same
//      random texts from startup in a reproducible way. After processing,
//      strrand() restores the former seed. Default is %F (false).
//      To use newSeed with the default charsets, use charsets = "".
//
//  T : Single or vector or matrix of text. T has the sizes of L.
//
//DESCRIPTION
// strrand(..) generates random characters, words or texts, according
// to specified lengths and characters content. Some predefined sets 
// of building characters are proposed. Average frequencies of 
// characters in output texts are their respective frequencies in 
// the building set (see PARAMETERS above, and EXAMPLES below).
// 
//SEE ALSO
// * getmd5   : http://help.scilab.org/docs/5.5.2/en_US/getmd5.html
// * tempname : http://help.scilab.org/docs/5.5.2/en_US/tempname.html
//
//REFERENCE: 
//  Comments, scoring and bug reports are welcome on
//  http://fileexchange.scilab.org/toolboxes/367000
//
//EXAMPLES
// strrand(15)
// strrand([10 3 8 0 15])
// strrand([6 40], "+AEIOUY")
// strrand([6 40], "+::xfr")
// strrand([6 40], "::hex")
// strrand([6 40], "::Hex")
// strrand([6 40], "::a:xfr")
// strrand([6 40], ",.::#:#rom")
// strrand(5:5:15, "::ja")
// strrand([6 40], "aaabbc")
//
//// Checking frequencies:
// s = strrand(6000, "aaabbc");
// members(['a' 'b' 'c'], strsplit(s)) / 1000
//
    fname = "strrand"
    // CHECKING INPUT PARAMETERS
    // -------------------------
    if  argn(2)==0
        head_comments(fname)
        T = []
        return
    end
    if ~isdef("L","l") then
        msg = _("%s: Lengths of texts are missing (arg#%d)\n")
        error(msprintf(msg, fname, 1))
    end
    if L==[] then
        T = []
        return
    end
    if type(L)~=1 | ~isreal(L) | or(L<0) then
        msg = _("%s: input argument #%d: positive integers expected\n")
        error(msprintf(msg, fname, 1))
    end
    if isdef("charsets","l") & ..
        (type(charsets)~=10 | size(charsets,"*")~=1) then
        msg = _("%s: Optional input argument #%d: Single text expected.\n")
        error(msprintf(msg, fname, 1))
    end
    if ~isdef("newSeed","l") | type(newSeed)~=4 then
        newSeed = %f
    end
    
    // PROCESSING
    // ----------
    defaultCharsets = ('a':'z')+('0':'9')
    if ~isdef('charsets','l') then
        charsets = "+"
    end
    if part(charsets,1)~="+" then
        source = charsets
    else
        source = defaultCharsets + part(charsets,2:$)
    end
    if source=="" then
        source = defaultCharsets
    end
    // Classes management
    tmp = strindex(source, "::")
    if tmp~=[] then
        tmp = strsplit(source,tmp($))
        chars = part(tmp(1), 1:$-1)
        tmp = strsplit(tmp(2), ":")
        classes = tmp(2:$)'
        
        CSets.a = "abcdefghijklmnopqrstuvwxyz"
        CSets.A = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        CSets.# = "0123456789"
        CSets.hex = "0123456789abcdef"
        CSets.Hex = "0123456789ABCDEF"
        CSets.#rom = "IVXLCDM" 
        CSets.xfr = "àâäçéèêëïôöùûü"
        CSets.xFr = "ÀÂÄÇÉÈÊËÏÔÖÙÛÜ"
        CSets.ru  = "абвгдеёжзийіклмнопрстуфхцчшщъыьѣэюяѳѵ"
        CSets.Ru  = "АБВГДЕЁЖЗИЙІКЛМНОПРСТУФХЦЧШЩЪЫЬѢЭЮЯѲѴ"
        CSets.xRu = "ѕЅѡѠѥѤѫѪѩѨѭѬѯѮѱѰ"
        CSets.ja  = "あいうえおはひふへほかきくけこまみむめもさしすせそ"+..
                    "やゆよたちつてとらりるれろなにぬねのわゐんゑを"
        F = fieldnames(CSets)'
        for c = classes
            if or (c==F) then
                chars = chars + CSets(c)
            end
        end
        source = chars
    end
    
    // Main job
    ns = length(source)
    source = strsplit(source)
    sL = size(L)

    L = L(:)
    N = sum(L)
    
    // Random generation
    if newSeed(1) then
        seed_old = grand("getsd")
        s = getdate(); 
        seed = pmodulo((((((s(1)-2000)*365.25+s(4))*24+s(7))*60+s(8))*60+s(9))*1000+s(10),2^32)
        grand("setsd", seed) 
        i = grand(1,N,"uin",1,ns)
        grand("setsd", seed_old)    // Restoring the former seed
    else
        i = grand(1,N,"uin",1,ns)        
    end

    t = strcat(source(i))
    
    if size(L,"*")>1 then
        t = strsplit(t, cumsum(L(1:$-1)))
    end
    T = matrix(t, sL)
endfunction
