#include <stdio.h>
#include <string.h>                             /* για memset()                      */
#include <stdlib.h>                             /* για exit(), calloc(), free(), κλπ */
#include <time.h>                               /* για time()                        */
 
#define MAXINBUF                (254+1)         /* μέγιστο μήκος γραμμής εισόδου     */
 
#define TABLE_BUF_MINLEN        5               /* ελάχιστο πλήθος στοιχείων         */
#define TABLE_BUF_EMPTYCELL     (-1)            /* για μαρκάρισμα κενών στοιχείων    */
 
typedef enum { FALSE=0, TRUE } Bool;            /* δικός μας πρόσθετος τύπος boolean */
 
typedef struct table {                          /* η βασική δομή του προγράμματος    */
        int bufmaxlen;                          /* ... μέγιστο πλήθος στοιχείων      */
        int buflen;                             /* ... τρέχον πλήθος στοιχείων       */
        int bufsize;                            /* ... μέγεθος στη μνήμη (σε bytes)  */
        int *buffer;                            /* ... ο πίνακας με τα στοιχεία      */
} Table;
 
/* --------------------------------------------------------------------------------
 * Αρχικοποιεί την δομή table με default τιμές βάσει του ορίσματος maxlen και
 * δημιουργεί το buffer της στη μνήμη.
 * Επιστρέφει FALSE σε περίπτωση που αποτύχει η δημιουργία του buffer ή αν το όρισμα
 * table περαστεί στη συνάρτηση με τιμή NULL, αλλιώς επιστρέφει TRUE.
 * --------------------------------------------------------------------------------
 */
 
Bool table_move2left(Table *table,int i)      {
    int tmp;
    
    for(;i < table->buflen-1;i++)       {
        tmp = table->buffer[i];
        table->buffer[i+1] = tmp;
    }
    return TRUE;
}
 
Bool table_init( Table *table, const int maxlen )
{
        if ( !table )                                   /* έλεγχος ασφαλείας          */
                return FALSE;                           /* ... πρόωρη έξοδος          */
 
                                                        /* μέγιστο πλήθος στοιχείων   */
        table->bufmaxlen = maxlen < TABLE_BUF_MINLEN ? TABLE_BUF_MINLEN : maxlen;
        table->buflen = 0;                              /* τρέχον πλήθος στοιχείων    */
        table->bufsize = table->bufmaxlen * sizeof(int);/* μεγέθος στη μνήμη σε bytes */
 
        table->buffer = malloc( table->bufsize );       /* δέσμευση μνήμης για buffer */
        if ( !table->buffer ) {                         /* αποτυχία δέσμευσης μνήμης  */
                table->bufsize = 0;                     /* ... μηδενισμός μεγέθους    */
                return FALSE;                           /* ... επιστροφή αποτυχίας    */
        }
                                        /* γέμισμα του buffer με TABLE_BUF_EMPTYCELL  */
        memset( table->buffer, TABLE_BUF_EMPTYCELL, table->bufsize );
 
        return TRUE;                                    /* επιστροφή επιτυχίας        */
}
/* --------------------------------------------------------------------------------
 * Μηδενίζει τα πεδία της δομής table, αποδεσμεύοντας και τη μνήμη του buffer.
 * Επιστρέφει FALSE αν το όρισμα table περαστεί στη συνάρτηση με τιμή NULL, αλλιώς
 * επιστρέφει TRUE.
 * --------------------------------------------------------------------------------
 */
Bool table_cleanup( Table *table )
{
        if ( !table )                                   /* έλεγχος ασφαλείας          */
                return FALSE;                           /* ... πρόωρη έξοδος          */
 
        if ( table->buffer ) {                          /* το buffer δεν είναι NULL   */
                free( table->buffer );                  /* ... αποδέσμευση της μνήμης */
                table->buffer = NULL;                   /* ... μηδενισμός του δείκτη  */
        }
                                                        /* μηδενισμός και των υπόλοιπων*/
        table->bufmaxlen = table->buflen = table->bufsize = 0;
 
        return TRUE;
}
/* --------------------------------------------------------------------------------
 * Γεμίζει το buffer της δομής table με ψευδοτυχαίες τιμές από 0 έως maxval.
 * Σε περίπτωση επιτυχίας ενημερώνει το τρέχον μήκος του buffer στη δομή κι επιστρέφει
 * TRUE. FALSE επιστρέφει όταν το buffer είναι ήδη γεμάτο ή δεν υπάρχει καν ή όταν το
 * όρισμα table περαστεί στη συνάρτηση με τιμή NULL.
 * --------------------------------------------------------------------------------
 */
Bool table_fill_randomly( Table *table, const int maxval )      {
        int i;
        if(!table || !table->buffer)    {
                printf("ΠΑΡΟΥΣΙΑΣΤΗΚΕ ΣΦΑΛΜΑ!");
                return FALSE;
        }
 
        if(table->buflen == table->bufmaxlen)   {
                printf("Ο ΠΙΝΑΚΑΣ ΕΙΝΑΙ ΓΕΜΑΤΟΣ!");
                return FALSE;
        }
 
        for(i = table->buflen;i < table->bufmaxlen;i++) {
                table->buffer[i] = rand() % maxval+1;
        }
        table->buflen = table->bufmaxlen;
        return TRUE;
}
//---------------------------------------------------------------------------------
 
/* --------------------------------------------------------------------------------
 * Τυπώνει στατιστικά σχετικά με το buffer της δομής table: μέγιστη χωρητικότητα σε
 * στοιχεία, πλήθος γεμάτων στοιχείων και μέγεθος που καταλαμβάνει σε bytes το buffer
 * στη μνήμη.
 * Επιστρέφει FALSE αν το όρισμα table περαστεί στη συνάρτηση με τιμή NULL, αλλιώς
 * επιστρέφει TRUE.
 * --------------------------------------------------------------------------------
 */
Bool table_print_info( Table table )
{
        if ( !table.buffer ) {                          /* έλεγχος ασφαλείας          */
                puts("Δεν βρέθηκε δημιουργημένος πίνακας!\n");
                return FALSE;                           /* ... πρόωρη έξοδος          */
        }
 
        printf("\n\tΜέγιστη χωρητικότητα:\t\t%d στοιχεία\n", table.bufmaxlen );
        printf("\tΠλήθος γεμάτων στοιχείων:\t%d\n",               table.buflen );
        printf("\tΜέγεθος πίνακα στη μνήμη:\t%d bytes\n",  table.bufsize );
        putchar('\n');
 
        return TRUE;
}
/* --------------------------------------------------------------------------------
 * Τυπώνει τα μη κενά στοιχεία του buffer της δομής table.
 * Επιστρέφει FALSE αν δεν υπάρχει δημιουργημένο buffer, αλλιώς επιστρέφει TRUE.
 * --------------------------------------------------------------------------------
 */
Bool table_print_buffer( Table table )
{
        register int i = 0;
 
        if ( !table.buffer ) {                          /* έλεγχος ασφαλείας          */
                puts("Δεν βρέθηκε δημιουργημένος πίνακας!\n");
                return FALSE;                           /* ... πρόωρη έξοδος          */
        }
 
        for (i=0; i < table.buflen; i++)                /* τύπωμα των στοιχείων       */
                printf("%d ", table.buffer[i] );
        putchar('\n');
 
        return TRUE;
}
/* --------------------------------------------------------------------------------
 * Διαβάζει από την κύρια είσοδο το μέγιστο πλήθος στοιχείων και το επιστρέφει
 * (απαιτεί το μέγιστο πλήθος να είναι μεγαλύτερο ή ίσο του TABLE_BUF_MINLEN).
 * --------------------------------------------------------------------------------
 */
int askuser_maxlen( void )
{
        char inbuf[ MAXINBUF ] = {'\0'};        /* δική μας γραμμή κύριας εισόδου    */
        int maxlen;                             /* η τιμή επιστροφής της συνάρτησης  */
 
        do {    /* απαίτηση πλήθους στοιχείων μεγαλύτερου από TABLE_BUF_MINLEN */
                printf("Μέγιστο πλήθος στοιχείων (τουλάχιστον %d): ", TABLE_BUF_MINLEN);
                fgets( inbuf, MAXINBUF, stdin );
                maxlen = atoi( inbuf );
        } while ( maxlen < TABLE_BUF_MINLEN );
 
        return maxlen;
}
/* --------------------------------------------------------------------------------
 *
 * --------------------------------------------------------------------------------
 */
 
Bool table_append(Table *table,int value)       {
        if(!table || !table->buffer || table->buflen == table->bufmaxlen || value < 0) return FALSE;
 
        table->buffer[(table->buflen)++] = value;
 
        return TRUE;
}
 
 
 
Bool table_insert(Table *table,int value,int posit)     {
    if(!table->buffer || table->buflen == table->bufmaxlen || value < 0) return FALSE;
        memmove(&table->buffer[posit-1],&table->buffer[posit],(table->buflen - (posit-1)) * sizeof(int));
    table->buffer[posit-1] = value;
    return TRUE;
}
 
Bool table_prepend(Table *table,int value)      {
 
        if(!table->buffer || table->buflen == table->bufmaxlen || value < 0)    return FALSE;
 
    memmove(&table->buffer[0],&table->buffer[1],table->buflen * sizeof(int));
 
        table->buffer[0] = value;
 
        return TRUE;
}
 
Bool table_update(Table *table,int value,int posit)     {
        if(!table || !table->buffer || value < 0) return FALSE;
        table->buffer[posit - 1] = value;       
        return TRUE;
}
 
Bool table_delete_pos(Table *table,int posit)   {
        if(!table || !table->buffer || posit < 0 || posit > table->bufmaxlen) return FALSE;
        memmove(&table->buffer[posit-1],&table->buffer[posit],table->buflen * sizeof(int));
        table->buffer[table->buflen--] = TABLE_BUF_EMPTYCELL;
        return TRUE;
}
 
Bool table_delete_num(Table *table, int value)  {
        int i;
        if(!table || !table->buffer || value < 0) return FALSE;
        for(i = 0;i < table->buflen && table->buffer[i] != value;i++);
        if(i > table->buflen) return FALSE;
        table_delete_pos(table,i);
        return TRUE;  
}
 
int main( void )
{
        Table   table;                          /* η βασική μας δομή                   */
        int     i,i2,maxlen = askuser_maxlen();      /* διάσβασμα μέγιστου πλήθους στοιχείων*/
                
        if ( !table_init( &table, maxlen ) )    /* αποτυχία αρχικοποίησης της δομής    */
        {                                       /* ...                                 */
                puts("*** αδυναμία δημιουργίας πίνακα, τερματισμός προγράμματος..." );
                exit( EXIT_FAILURE );           /* ... τερματισμός αποτυχίας           */
        }
 
        puts("\nΟ πίνακας δημιουργήθηκε & αρχικοποιήθηκε επιτυχώς!");
                
                scanf("%d",&i);
 
                table_prepend(&table,i);
                
                scanf("%d",&i2);
                
        table_append(&table,i2);
        
        table_delete_num(&table,2);
 
        srand( time(NULL) );                    /* ενεργοποίηση γεννήτριας ψευδοτυχαίων*/
 
        table_print_info( table );              /* τύπωμα στατιστικών                  */
 
        table_print_buffer( table );            /* τύπωμα περιεχομένων του buffer      */
 
        table_cleanup( &table );                /* μηδενισμός δομής, αποδέσμευση buffer*/
 
        exit( EXIT_SUCCESS );                   /* τερματισμός επιτυχίας               */
}