class Context {
private State state;
int[][] matrix;
public int left, right, top, bottom;
public int i, j;
public Context(int[][] matrix) {
this.state = new Right();
this.matrix = matrix;
i = 0;
j = 0;
left = 0;
top = 0;
bottom = matrix == null ? -1 : matrix.length - 1;
right = (matrix == null || matrix.length == 0 || matrix[0] == null) ? -1 : matrix[0].length - 1;
}
public int next() {
return state.next(this);
}
public void setState(State state) {
this.state = state;
}
public int getCurrent() {
return matrix[i][j];
}
public boolean hasNext() {
return j >= left && j <= right && i >= top && i <= bottom;
}
}
abstract class State {
public abstract int next(Context context);
}
class Right extends State {
@Override
public int next(Context context) {
int ans = context.getCurrent();
if (context.j == context.right) {
context.i++;
context.top++;
context.setState(new Bottom());
} else {
context.j++;
}
return ans;
}
}
class Bottom extends State {
@Override
public int next(Context context) {
int ans = context.getCurrent();
if (context.i == context.bottom) {
context.j--;
context.right--;
context.setState(new Left());
} else {
context.i++;
}
return ans;
}
}
class Left extends State {
@Override
public int next(Context context) {
int ans = context.getCurrent();
if (context.j == context.left) {
context.i--;
context.bottom--;
context.setState(new Top());
} else {
context.j--;
}
return ans;
}
}
class Top extends State {
@Override
public int next(Context context) {
int ans = context.getCurrent();
if (context.i == context.top) {
context.j++;
context.left++;
context.setState(new Right());
} else {
context.i--;
}
return ans;
}
}
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> ans = new ArrayList<>();
Context context = new Context(matrix);
while (context.hasNext()) {
ans.add(context.next());
}
return ans;
}