/**
 * Text file reader. Allows to read a text file line by line. Some basic path
 * and file names manipulation routines are also provided.
 * 
 * @file
 * @author Umberto Salsi <salsi@icosaedro.it>
 * @version $Date: 2017/11/02 07:43:53 $
 */

#ifndef READER_H
#define READER_H

#ifdef reader_IMPORT
	#define EXTERN
#else
	#define EXTERN extern
#endif

/**
 * State of the reader.
 */
typedef struct reader_Type reader_Type;

/**
 * Opens a text file for reading. On error, the error string is set and any
 * further read request fails.
 * @return New reader_Type. Must be released with memory_dispose().
 */
EXTERN reader_Type * reader_new(char *path);

/**
 * Gets the next line from file. Leading spaces, trailing spaces and
 * new-line are removed.
 * @param this
 * @param line Destination buffer for the line.
 * @param line_capacity Destination buffer capacity.
 * @return True if a new line is available, or false on end of the file or
 * error.
 */
EXTERN int    reader_getLine(reader_Type *this, char *line, int line_capacity);

/** Returns the path of the file being read. */
EXTERN char * reader_getPath(reader_Type *this);

/** Returns the line number of the line just read; first line is no. 1. */
EXTERN int    reader_getLineNumber(reader_Type *this);

/**
 * Returns the description of the last error occurred.
 * @param this
 * @return Description of the last error occurred, or NULL if no error.
 */
EXTERN char * reader_getError(reader_Type *this);


/* ----------------  UTILITIES  -------------------------------------------- */

/**
 * Returns true if the path is absolute.
 * 
 * A NULL or empty string is an absolute path (!).
 * 
 * Under Unix and Linux, a path is absolute if it starts with slash '/'.
 * 
 * Under Windows, a path is considered absolute if one of this conditions holds:
 * 1. it starts with slash '/' or back-slash '\' or:
 * 2. it starts with a letter followed by ':'.
 * Note that a drive letter followed by a relative path like "C:y\z" is assumed
 * to be absolute, although the "y\z" path is actually a relative path.
 * 
 * FIXME: naive implementation as it does not account for duplicates slashes nor
 * special paths "." and "..".
 * 
 * @param path
 * @return True if the path is absolute.
 */
EXTERN int reader_isAbsolute(char *path);

/**
 * Resolves the relative path of a file specified inside another file.
 * Example: the file "models/data.txt" contains a relative reference to the
 * file "data2.txt" then the returned path is "models/data2.txt".
 * @param from File name containing the path.
 * @param to File name contained inside the file above. If already absolute,
 * does nothing and returns a copy of this path.
 * @return Resolved file path. The returned name is dynamically allocated and
 * must be released with memory_dispose().
 */
EXTERN char * reader_resolveRelativePath(char *from, char *to);

/**
 * Returns true if the file is readable.
 * @param path
 * @return True if the file is readable.
 */
EXTERN int reader_isReadable(char *path);

/**
 * Split the string into fields separated by white spaces.
 * @param s Line to split in place. Beware: the content of this string gets
 * modified to add the NUL string terminators after each found field.
 * @param argc Here returns the number of parsed fields.
 * @param argv Here returns the pointers to the split fields.
 * @param argv_capacity Maximum number of fields.
 * @return True on success; false if there are too many fields and only the
 * first argv_capacity have been parsed and returned.
 */
EXTERN int reader_split(char *s, int *argc, char *argv[], int argv_capacity);

/**
 * Split the string into fields separated by comma. Double-quotes can be used
 * to include spaces (which are otherwise ignored) and the comma itself.
 * Inside double-quotes, two consecutive double-quote characters are a returned
 * as a single double quote (double-quote escaping).
 * @param s Line to split in place. Beware: the content of this string gets
 * modified to add the NUL string terminators after each found field.
 * @param argc Here returns the number of parsed fields.
 * @param argv Here returns the pointers to the split fields.
 * @param argv_capacity Maximum number of fields.
 * @return True on success; false if there are too many fields and only the
 * first argv_capacity have been parsed and returned.
 */
EXTERN int reader_splitDoubleQuotedCommaSeparated(char *s, int *argc, char *argv[], int argv_capacity);

#undef EXTERN
#endif
