/* MODIFICATORI 
CLASSI
  public: visibile anche all'esterno del pacchetto in cui è definita 
  abstract: non istanziabile
  final: non ereditabile

ATTRIBUTI
  public: visibile anche all'esterno della classe in cui è definito
  private: visibile solo nella classe in cui è definito
  protected: visibile nelle sottoclassi e nelle altre classi dello stesso pacchetto
  static: di classe (altrimenti di istanza)
  final: non modificabile (costante)

METODI
  public: visibile anche all'esterno della classe in cui è definito
  private: visibile solo nella classe in cui è definito
  protected: visibile nelle sottoclassi e nelle altre classi dello stesso pacchetto
  abstract: non viene specificato il corpo del metodo
  static: di classe (altrimenti di istanza)
  final: non sovrascrivibile

CONVENZIONI:
  *) il nome delle classi inizia con una maiuscola
  *) il nome degli attributi e dei metodi inizia con una minuscola
  *) le costanti tutte in maiuscolo
  *) se un nome è costituito da più parole, la lettera iniziale di ogni parola è maiuscola
     (InsertionSort) e separata da _ per le costanti (MAX_VALUE) 
*/

// importo tutte le classi del pacchetto java.lang; 
// il pacchetto java.lang è sempre importato implicitamente
import java.lang.*;

// una unica classe public per file il cui nome coincide con il nome del file
public class InsertionSort {
    
  // MIN_VALUE e MAX_VALUE sono attributi di classe non modificabili (costanti)
  static final int MIN_VALUE = 0;
  static final int MAX_VALUE = 100;

  // il metodo main è invocato quando la classe viene eseguita; 
  // deve sempre avere questa intestazione
  public static void main(String[] args) {    
    
    // dichiarazione della variabile len
    int len;
    
    
    if (args.length != 1) {
      // out è un attributo di classe della classe System definita nel pacchetto java.lang;
      // println è un metodo di istanza dell'oggetto out
      System.out.println("Uso: java InsertionSort #elementi");
      // exit è un metodo di classe di System
      System.exit(1);
    }  
      
    // assegnamento della variabile len; 
    // parseInt è un metodo di classe della classe Integer definita nel pacchetto java.lang    
    len = Integer.parseInt(args[0]);
    
    if (len < 0) {
      System.out.println("Il numero di elementi deve essere positivo");
      System.exit(1);
    }  

    
    // dichiarazione e assegnazione di un vettore nella stessa instruzione; 
    // randomArray è un metodo di classe della classe Random definita in questo file 
    int[] a = Random.randomArray(MIN_VALUE, MAX_VALUE, len);

    // metodo di classe di questa classe (InsertionSort); 
    // non occorre farlo precedere dal nome della classe 
    insertionSort(a);

    for (int i = 0; i < a.length; i++) {
      System.out.print(a[i] + " ");
    }
    System.out.println();        
  } 
 

  /** ordina un vettore in senso crescente */
  // insertionSort è un metodo di classe  
  public static void insertionSort(int[] a) {
  
    int i, j, key;
    
    for (j = 1; j < a.length; j++) {
      key = a[j];
      i = j-1;
      while ((i >= 0) && (key < a[i])) {
        a[i+1] = a[i];
        i--;
      }
	    a[i+1] = key;
    }      
  }

}


class Random {

  /** Restituisce un intero pseudo-casuale tra a e b (con b >= a >= 0)  */
  // random è un metodo di classe
  public static int random(int a, int b) {
    
    // random() è un metodo di classe della classe Math definita nel pacchetto java.lang
    return a + (int) (Math.random() * (b - a + 1));
  }

  /** Restituisce un vettore di k interi pseudo-causali tra a e b */
  // randomArray è un metodo di classe
  public static int[] randomArray(int a, int b, int k) {
    
    // new type è il costruttore di oggetti di tipo type
    int[] v = new int[k];
    for (int i = 0; i < k; i++) {
      v[i] = random(a, b);
    }
    return v;
  }
  
}

